Files
metasploit-gs/external/source/exploits/drunkpotato/Common_Src_Files/Services/service.c
T
2020-12-07 23:26:36 -05:00

252 lines
7.2 KiB
C

#include "..\pch.h"
/**
This module is a plain C class emulation. The POC written by decoder was in cpp and used some classes
in particular for the local negotiator.
See https://stackoverflow.com/questions/40992945/convert-a-cpp-class-cpp-file-into-a-c-structure-c-file
for how I emulated a class in pure C.
This class defines a base server object. Inheritance will be emulated in order to create a
Rogue WinRM service and a simple http server derived from this class.
*/
/**
Constructor of the Server class. Setup the addresses of class methods,
and initialize some arguments
@param Server* this Address of the instantiated object.
@param char* listen_address Address of IP (as string)
@param char* listen_port Address of port (as string)
@param BOOL debug TRUE or FALSE. Defined in main/dllmain
*/
void initService(Server* this, char* listen_address, char* listen_port)
{
ZeroMemory(this, sizeof(Server));
this->destruct = &destructService;
this->listenerStart = &startListener;
this->serverStop = &SocketError;
this->listen_address = listen_address;
this->listen_port = listen_port;
this->socket = INVALID_SOCKET;
this->socketInfos = NULL;
ZeroMemory(&this->hints, sizeof(this->hints));
this->hints.ai_family = AF_INET;
this->hints.ai_socktype = SOCK_STREAM;
this->hints.ai_protocol = IPPROTO_TCP;
this->hints.ai_flags = AI_PASSIVE;
this->listenerStart(this);
return;
}
/**
Destructor of the Server class. Free allocated memory.
@param Server* this Address of the instantiated object.
*/
void destructService(Server* this)
{
/*for (this->allocationMapLen=10; this->allocationMapLen > 0; this->allocationMapLen--)
{
free(this->allocationMap[this->allocationMapLen]);
}*/
return;
}
/**
Initialization of the server :
- Initialize Winsock
- Resolve the server address and port
- Create a SOCKET for connecting to server
- Setup the TCP listening socket
- Accept a client socket and put it as argument to make it available for derived servers.
- Clean the listen socket
@param Server* this Address of the instantiated object.
*/
static void startListener(Server* this)
{
int iResult = -1;
WSADATA wsaData;
SOCKET ListenSocket = INVALID_SOCKET;
struct addrinfo* result = NULL;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0)
{
dprintf("[startListener] ERROR: WSAStartup failed with error: %d", iResult);
exit(-1);
}
dprintf("[startListener] SUCCESS: WSAStartup initialized");
// Resolve the server address and port
iResult = getaddrinfo(this->listen_address, this->listen_port, &this->hints, &this->socketInfos);
if (iResult != 0)
{
dprintf("[startListener] ERROR: getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
exit(-1);
}
dprintf("[startListener] SUCCESS: getaddrinfo initialized. host:%s, port: %s", this->listen_address, this->listen_port);
// Create a SOCKET for connecting to server
ListenSocket = socket(this->socketInfos->ai_family, this->socketInfos->ai_socktype, this->socketInfos->ai_protocol);
if (ListenSocket == INVALID_SOCKET)
{
dprintf("[startListener] ERROR: socket creation failed with error: %ld\n", WSAGetLastError());
freeaddrinfo(this->socketInfos);
WSACleanup();
exit(-1);
}
dprintf("[startListener] SUCCESS: socket created.");
// Setup the TCP listening socket
iResult = bind(ListenSocket, this->socketInfos->ai_addr, (int)this->socketInfos->ai_addrlen);
if (iResult == SOCKET_ERROR)
{
if (strcmp(this->listen_port, "5985") == 0) { dprintf("[startListener] ERROR: WinRM already running on port 5985. Unexploitable!"); }
dprintf("[startListener] ERROR: bind failed with error: %d", WSAGetLastError());
freeaddrinfo(this->socketInfos);
this->serverStop(this, ListenSocket, "[startListener] ERROR: bind failed");
}
dprintf("[startListener] SUCCESS: socket bound.");
freeaddrinfo(this->socketInfos);
iResult = listen(ListenSocket, SOMAXCONN);
if (iResult == SOCKET_ERROR) { this->serverStop(this, ListenSocket, "[startListener] ERROR: Listen stage failed"); }
dprintf("[startListener] SUCCESS: socket is now listening for incoming connexions.");
// Accept a client socket
this->socket = accept(ListenSocket, NULL, NULL);
if (this->socket == INVALID_SOCKET) { this->serverStop(this, this->socket, "[startListener] ERROR: Accept stage failed"); }
dprintf("[startListener] SUCCESS: socket accept stage successful.");
// No longer need server socket
closesocket(ListenSocket);
return;
}
/**
In case of failure, close properly the server:
- Shutdown this->socket
- Close this->socket
- Invoke the class destructor
@param Server* this Address of the instantiated object
@param SOCKET Socket Socket to close. If -1, then set it to this->socket
@param char* error_message Message to be displayed
*/
static void SocketError(Server* this, SOCKET Socket, char* error_message)
{
if (Socket == -1) { Socket = this->socket; }
dprintf("[SocketError] SOCKET ERROR: WSAGetLastError: %d", WSAGetLastError());
dprintf("%s", error_message);
shutdown(Socket, SD_SEND);
closesocket(Socket);
WSACleanup();
this->destruct(this);
exit(-1);
}
/**
Print network packets received or to be send for debug purposes in tcpdump style.
This function is only for debug purpose. If DEBUGTRACE preprocessor constant is
not set, this function returns immediately without doing anything.
*/
void hexDump_if_debug_env(char* desc, void* addr, int len)
{
#ifdef DEBUGTRACE
int i;
int written_chars = 0;
unsigned char buff[17];
unsigned char temporary_buff[20] = { 0 };
unsigned char line[74] = { 0 };
unsigned char* pc = (unsigned char*)addr;
// Output description if given.
if (desc != NULL)
dprintf("[hexDump] %s:\n", desc);
if (len == 0)
{
dprintf("[hexDump] ERROR: data are zero length.");
return;
}
if (len < 0)
{
dprintf("[hexDump] ERROR: data are negative length.: %i", len);
return;
}
dprintf("[hexDump] Hexdump of packet:");
// Process every byte in the data.
for (i = 0; i < len; i++)
{
// Multiple of 16 means new line (with line offset).
if ((i % 16) == 0)
{
// Just don't print ASCII for the zeroth line.
if (i != 0)
{
strcat_s(line, 74, " ");
strcat_s(line, 74, buff);
dprintf("[hexDump] %s", line);
ZeroMemory(line, 74);
}
// Put the offset in line buffer.
written_chars = sprintf_s(temporary_buff, 20, " %04x ", i);
strcat_s(line, 74, temporary_buff);
ZeroMemory(temporary_buff, 20);
}
// Now the hex code for the specific character.
written_chars = sprintf_s(temporary_buff, 20, " %02x", pc[i]);
strcat_s(line, 74, temporary_buff);
ZeroMemory(temporary_buff, 20);
// And store a printable ASCII character for later.
if ((pc[i] < 0x20) || (pc[i] > 0x7e))
buff[i % 16] = '.';
else
buff[i % 16] = pc[i];
buff[(i % 16) + 1] = '\0';
}
// Pad out last line if not exactly 16 characters.
while ((i % 16) != 0)
{
written_chars = sprintf_s(temporary_buff, 20, " ");
strcat_s(line, 74, temporary_buff);
ZeroMemory(temporary_buff, 20);
i++;
}
// And print the final ASCII bit.
written_chars = sprintf_s(temporary_buff, 20, " %s\n", buff);
strcat_s(line, 74, temporary_buff);
ZeroMemory(temporary_buff, 20);
dprintf("[hexDump] %s", line);
#endif
return;
}