diff --git a/c/meterpreter/source/common/common.h b/c/meterpreter/source/common/common.h index e13f7fc0..aeb0d5d2 100755 --- a/c/meterpreter/source/common/common.h +++ b/c/meterpreter/source/common/common.h @@ -12,7 +12,7 @@ #include #include -#define SAFE_FREE(x) {free(x); x = NULL;} +#define SAFE_FREE(x) if(x){free(x);x=NULL;} #include #include diff --git a/c/meterpreter/source/common/pivot_tree.c b/c/meterpreter/source/common/pivot_tree.c index 73e5875a..35723daa 100755 --- a/c/meterpreter/source/common/pivot_tree.c +++ b/c/meterpreter/source/common/pivot_tree.c @@ -23,19 +23,23 @@ DWORD pivot_tree_add_node(PivotNode* parent, PivotNode* node) { if (parent->left == NULL) { + dprintf("[PIVOTTREE] Adding node to left"); parent->left = node; return ERROR_SUCCESS; } + dprintf("[PIVOTTREE] Adding node to left subtree"); return pivot_tree_add_node(parent->left, node); } if (parent->right == NULL) { + dprintf("[PIVOTTREE] Adding node to right"); parent->right = node; return ERROR_SUCCESS; } + dprintf("[PIVOTTREE] Adding node to right subtree"); return pivot_tree_add_node(parent->right, node); } @@ -44,7 +48,7 @@ DWORD pivot_tree_add(PivotTree* tree, LPBYTE guid, PivotContext* ctx) PivotNode* node = (PivotNode*)calloc(1, sizeof(PivotNode)); #ifdef DEBUGTRACE PUCHAR h = (PUCHAR)&guid[0]; - dprintf("[PIVOTTREE] Adding Session GUID: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", + dprintf("[PIVOTTREE] Adding GUID: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15]); #endif @@ -74,14 +78,16 @@ PivotNode* pivot_tree_largest_node(PivotNode* node) return pivot_tree_largest_node(node->right); } -DWORD pivot_tree_remove_node(PivotNode* parent, LPBYTE guid) +PivotContext* pivot_tree_remove_node(PivotNode* parent, LPBYTE guid) { int cmp = memcmp(parent->guid, guid, sizeof(parent->guid)); if (cmp < 0 && parent->left != NULL) { + dprintf("[PIVOTTREE] Removing from left subtree"); int cmp = memcmp(parent->left->guid, guid, sizeof(parent->guid)); if (cmp == 0) { + dprintf("[PIVOTTREE] Removing right child"); PivotNode* remove = parent->left; PivotNode* left = remove->left; PivotNode* largest = pivot_tree_largest_node(left); @@ -96,8 +102,9 @@ DWORD pivot_tree_remove_node(PivotNode* parent, LPBYTE guid) parent->left = remove->right; } + PivotContext* context = remove->ctx; free(remove); - return ERROR_SUCCESS; + return context; } return pivot_tree_remove_node(parent->left, guid); @@ -105,9 +112,11 @@ DWORD pivot_tree_remove_node(PivotNode* parent, LPBYTE guid) if (cmp > 0 && parent->right != NULL) { + dprintf("[PIVOTTREE] Removing from right subtree"); int cmp = memcmp(parent->right->guid, guid, sizeof(parent->guid)); if (cmp == 0) { + dprintf("[PIVOTTREE] Removing right child"); PivotNode* remove = parent->right; PivotNode* left = remove->left; PivotNode* largest = pivot_tree_largest_node(left); @@ -122,27 +131,35 @@ DWORD pivot_tree_remove_node(PivotNode* parent, LPBYTE guid) parent->right = remove->right; } + PivotContext* context = remove->ctx; free(remove); - return ERROR_SUCCESS; + return context; } return pivot_tree_remove_node(parent->left, guid); } - return ERROR_SUCCESS; + return NULL; } -DWORD pivot_tree_remove(PivotTree* tree, LPBYTE guid) +PivotContext* pivot_tree_remove(PivotTree* tree, LPBYTE guid) { +#ifdef DEBUGTRACE + PUCHAR h = (PUCHAR)&guid[0]; + dprintf("[PIVOTTREE] Removing GUID: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", + h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15]); +#endif + if (tree->head == NULL) { - return ERROR_SUCCESS; + return NULL; } int cmp = memcmp(tree->head->guid, guid, sizeof(tree->head->guid)); if (cmp == 0) { + dprintf("[PIVOTTREE] Removing head node"); PivotNode* remove = tree->head; PivotNode* left = tree->head->left; PivotNode* largest = pivot_tree_largest_node(left); @@ -157,10 +174,12 @@ DWORD pivot_tree_remove(PivotTree* tree, LPBYTE guid) tree->head = tree->head->right; } + PivotContext* context = remove->ctx; free(remove); - return ERROR_SUCCESS; + return context; } + dprintf("[PIVOTTREE] Removing non-head node"); return pivot_tree_remove_node(tree->head, guid); } @@ -174,24 +193,27 @@ PivotContext* pivot_tree_find_node(PivotNode* node, LPBYTE guid) #ifdef DEBUGTRACE PUCHAR h = (PUCHAR)&guid[0]; - dprintf("[PIVOTTREE] Session GUID: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", + dprintf("[PIVOTTREE] Saerch GUID: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15]); h = node->guid; - dprintf("[PIVOTTREE] Node GUID: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", + dprintf("[PIVOTTREE] Node GUID: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15]); #endif - int cmp = memcmp(guid, node->guid, sizeof(guid)); + int cmp = memcmp(node->guid, guid, sizeof(node->guid)); if (cmp == 0) { + dprintf("[PIVOTTREE] node found"); return node->ctx; } if (cmp < 0) { + dprintf("[PIVOTTREE] Searching left subtree"); return pivot_tree_find_node(node->left, guid); } + dprintf("[PIVOTTREE] Searching right subtree"); return pivot_tree_find_node(node->right, guid); } diff --git a/c/meterpreter/source/common/pivot_tree.h b/c/meterpreter/source/common/pivot_tree.h index 3be8e995..b9b61e65 100755 --- a/c/meterpreter/source/common/pivot_tree.h +++ b/c/meterpreter/source/common/pivot_tree.h @@ -2,10 +2,12 @@ #define _METERPRETER_PIVOT_TREE typedef DWORD(*PivotWritePacket)(LPVOID state, LPBYTE rawPacket, DWORD rawPacketLength); +typedef DWORD(*PivotRemove)(LPVOID state); typedef struct _PivotContext { PivotWritePacket packet_write; + PivotRemove remove; LPVOID state; } PivotContext; @@ -20,7 +22,7 @@ typedef void(*PivotTreeTraverseCallback)(LPBYTE guid, PivotContext* ctx, LPVOID PivotTree* pivot_tree_create(); DWORD pivot_tree_add(PivotTree* tree, LPBYTE guid, PivotContext* ctx); -DWORD pivot_tree_remove(PivotTree* tree, LPBYTE guid); +PivotContext* pivot_tree_remove(PivotTree* tree, LPBYTE guid); PivotContext* pivot_tree_find(PivotTree* tree, LPBYTE guid); void pivot_tree_traverse(PivotTree* tree, PivotTreeTraverseCallback callback, LPVOID state); void pivot_tree_destroy(PivotTree* tree); diff --git a/c/meterpreter/source/common/remote.c b/c/meterpreter/source/common/remote.c index d66ee34a..8a11f414 100755 --- a/c/meterpreter/source/common/remote.c +++ b/c/meterpreter/source/common/remote.c @@ -27,7 +27,8 @@ Remote* remote_allocate() remote->lock = lock; remote->enc_ctx = NULL; - remote->pivots = pivot_tree_create(); + remote->pivot_sessions = pivot_tree_create(); + remote->pivot_listeners = pivot_tree_create(); dprintf("[REMOTE] remote created %p", remote); return remote; @@ -38,9 +39,14 @@ Remote* remote_allocate() lock_destroy(lock); } - if (remote->pivots) + if (remote->pivot_sessions) { - pivot_tree_destroy(remote->pivots); + pivot_tree_destroy(remote->pivot_sessions); + } + + if (remote->pivot_listeners) + { + pivot_tree_destroy(remote->pivot_listeners); } if (remote) @@ -59,7 +65,8 @@ Remote* remote_allocate() VOID remote_deallocate(Remote * remote) { free_encryption_context(remote); - pivot_tree_destroy(remote->pivots); + pivot_tree_destroy(remote->pivot_sessions); + pivot_tree_destroy(remote->pivot_listeners); if (remote->lock) { diff --git a/c/meterpreter/source/common/remote.h b/c/meterpreter/source/common/remote.h index f0e46be1..bda8cc51 100755 --- a/c/meterpreter/source/common/remote.h +++ b/c/meterpreter/source/common/remote.h @@ -160,7 +160,8 @@ typedef struct _Remote int sess_expiry_end; ///! Unix timestamp for when the server should shut down. int sess_start_time; ///! Unix timestamp representing the session startup time. - PivotTree* pivots; ///! Collection of active Meterpreter session pivots. + PivotTree* pivot_sessions; ///! Collection of active Meterpreter session pivots. + PivotTree* pivot_listeners; ///! Collection of active Meterpreter pivot listeners. PacketEncryptionContext* enc_ctx; ///! Reference to the packet encryption context. } Remote; diff --git a/c/meterpreter/source/server/remote_dispatch_common.c b/c/meterpreter/source/server/remote_dispatch_common.c index 948685b3..be289fd9 100755 --- a/c/meterpreter/source/server/remote_dispatch_common.c +++ b/c/meterpreter/source/server/remote_dispatch_common.c @@ -23,6 +23,7 @@ Command customCommands[] = COMMAND_REQ("core_set_session_guid", request_core_set_session_guid), COMMAND_REQ("core_set_uuid", request_core_set_uuid), COMMAND_REQ("core_pivot_add", request_core_pivot_add), + COMMAND_REQ("core_pivot_remove", request_core_pivot_remove), COMMAND_INLINE_REP("core_patch_url", request_core_patch_url), COMMAND_TERMINATOR }; diff --git a/c/meterpreter/source/server/win/server_pivot.c b/c/meterpreter/source/server/win/server_pivot.c index fdb568e2..3dcdee7b 100755 --- a/c/meterpreter/source/server/win/server_pivot.c +++ b/c/meterpreter/source/server/win/server_pivot.c @@ -15,4 +15,31 @@ DWORD request_core_pivot_add(Remote* remote, Packet* packet) { // Right now we only support named pipe pivotes, so just go straight there return request_core_pivot_add_named_pipe(remote, packet); +} + +/*! + * @brief Remove a pivot point from the current Meterpreter instance. + * @remote Pointer to the \c Remote instance. + * @remote Pointer to the incoming request \c Packet instance. + * @return Indication of error or success. + */ +DWORD request_core_pivot_remove(Remote* remote, Packet* packet) +{ + DWORD result = ERROR_NOT_FOUND; + LPBYTE pivotId = packet_get_tlv_value_raw(packet, TLV_TYPE_PIVOT_ID); + + if (pivotId != NULL) + { + PivotContext* ctx = pivot_tree_remove(remote->pivot_listeners, pivotId); + if (ctx != NULL) + { + ctx->remove(ctx->state); + free(ctx); + result = ERROR_SUCCESS; + } + } + + packet_transmit_empty_response(remote, packet, result); + + return result; } \ No newline at end of file diff --git a/c/meterpreter/source/server/win/server_pivot.h b/c/meterpreter/source/server/win/server_pivot.h index 0981fc6d..94d0b6a5 100755 --- a/c/meterpreter/source/server/win/server_pivot.h +++ b/c/meterpreter/source/server/win/server_pivot.h @@ -1,6 +1,7 @@ #ifndef _METERPRETER_SERVER_PIVOT #define _METERPRETER_SERVER_PIVOT -DWORD request_core_pivot_add(Remote* remote, Packet* packet); +DWORD request_core_pivot_add(Remote* remote, Packet* packet); +DWORD request_core_pivot_remove(Remote* remote, Packet* packet); #endif \ No newline at end of file diff --git a/c/meterpreter/source/server/win/server_pivot_named_pipe.c b/c/meterpreter/source/server/win/server_pivot_named_pipe.c index 2058d9e6..f89d14a8 100755 --- a/c/meterpreter/source/server/win/server_pivot_named_pipe.c +++ b/c/meterpreter/source/server/win/server_pivot_named_pipe.c @@ -16,6 +16,7 @@ typedef struct _NamedPipeContext OVERLAPPED write_overlap; char name[PIPE_NAME_SIZE]; GUID pivot_id; + GUID pivot_session_guid; Remote* remote; HANDLE pipe; BOOL connecting; @@ -30,6 +31,7 @@ typedef struct _NamedPipeContext } NamedPipeContext; static DWORD server_notify(Remote* remote, LPVOID entryContext, LPVOID threadContext); +static DWORD server_destroy(HANDLE waitable, LPVOID entryContext, LPVOID threadContext); typedef BOOL (WINAPI *PAddMandatoryAce)(PACL pAcl, DWORD dwAceRevision, DWORD dwAceFlags, DWORD dwMandatoryPolicy, PSID pLabelSid); static BOOL WINAPI AddMandatoryAce(PACL pAcl, DWORD dwAceRevision, DWORD dwAceFlags, DWORD dwMandatoryPolicy, PSID pLabelSid) @@ -57,6 +59,38 @@ static BOOL WINAPI AddMandatoryAce(PACL pAcl, DWORD dwAceRevision, DWORD dwAceFl return TRUE; } +static DWORD server_destroy(HANDLE waitable, LPVOID entryContext, LPVOID threadContext) +{ + NamedPipeContext* ctx = (NamedPipeContext*)entryContext; + if (ctx != NULL) + { + dprintf("[PIVOT] Cleaning up the pipe pivot context"); + lock_acquire(ctx->remote->lock); + CloseHandle(ctx->pipe); + CloseHandle(ctx->read_overlap.hEvent); + CloseHandle(ctx->write_overlap.hEvent); + SAFE_FREE(ctx->stage_data); + lock_release(ctx->remote->lock); + dprintf("[PIVOT] Cleaned up the pipe pivot context"); + } + return ERROR_SUCCESS; +} + +static void terminate_pipe(NamedPipeContext* ctx) +{ + if (ctx != NULL) + { + scheduler_signal_waitable(ctx->read_overlap.hEvent, Stop); + } +} + +static DWORD remove_listener(LPVOID state) +{ + dprintf("[PIVOT] removing named pipe listener"); + terminate_pipe((NamedPipeContext*)state); + return ERROR_SUCCESS; +} + static DWORD read_pipe_to_packet(NamedPipeContext* ctx, LPBYTE source, DWORD sourceSize) { // Make sure we have the space to handle the incoming packet @@ -315,7 +349,8 @@ DWORD create_pipe_server_instance(NamedPipeContext* ctx) } dprintf("[NP-SERVER] Inserting the named pipe schedule entry"); - scheduler_insert_waitable(ctx->read_overlap.hEvent, ctx, NULL, server_notify, NULL); + scheduler_insert_waitable(ctx->read_overlap.hEvent, ctx, NULL, server_notify, server_destroy); + //scheduler_insert_waitable(ctx->read_overlap.hEvent, ctx, NULL, server_notify, NULL); } while (0); return dwResult; @@ -429,8 +464,23 @@ static DWORD server_notify(Remote* remote, LPVOID entryContext, LPVOID threadCon else if (dwResult == ERROR_BROKEN_PIPE) { dprintf("[NP-SERVER] the client appears to have bailed out, disconnecting..."); + // Reset the read event so that our schedular loop witll exit properly ResetEvent(serverCtx->read_overlap.hEvent); - // TODO: do some clean up of stuf here. + + // Prepare the notification packet for dispatching + Packet* notification = packet_create(PACKET_TLV_TYPE_REQUEST, "core_pivot_session_died"); + packet_add_tlv_raw(notification, TLV_TYPE_SESSION_GUID, (LPVOID)&serverCtx->pivot_session_guid, sizeof(serverCtx->pivot_session_guid)); + + // Clean up the pivot context + PivotContext* pivotCtx = pivot_tree_remove(remote->pivot_sessions, (LPBYTE)&serverCtx->pivot_session_guid); + SAFE_FREE(pivotCtx); + + // Clean up all the named pipe context stuff. + terminate_pipe(serverCtx); + + // Inform MSF of the dead session + packet_transmit(serverCtx->remote, notification, NULL); + return ERROR_BROKEN_PIPE; } break; @@ -454,6 +504,7 @@ static DWORD server_notify(Remote* remote, LPVOID entryContext, LPVOID threadCon nextCtx->remote = serverCtx->remote; nextCtx->stage_data = serverCtx->stage_data; nextCtx->stage_data_size = serverCtx->stage_data_size; + memcpy_s(&nextCtx->pivot_id, sizeof(nextCtx->pivot_id), &serverCtx->pivot_id, sizeof(nextCtx->pivot_id)); memcpy_s(&nextCtx->name, PIPE_NAME_SIZE, &serverCtx->name, PIPE_NAME_SIZE); // create a new pipe for the next connection @@ -466,6 +517,16 @@ static DWORD server_notify(Remote* remote, LPVOID entryContext, LPVOID threadCon serverCtx->established = TRUE; + // The current listener cotnext in the listeners tree points to the server instance that has now + // become a client instance due to the new connection. Therefore we need to update the pivot tree context + // to point to the new listener on the named pipe. + PivotContext* listenerCtx = pivot_tree_find(remote->pivot_listeners, (LPBYTE)&serverCtx->pivot_id); + if (listenerCtx != NULL) + { + dprintf("[NP-SERVER] Updating the listener context in the pivot tree"); + listenerCtx->state = nextCtx; + } + // Time to stage the data if (serverCtx->stage_data && serverCtx->stage_data_size > 0) { @@ -475,25 +536,29 @@ static DWORD server_notify(Remote* remote, LPVOID entryContext, LPVOID threadCon // send the stage named_pipe_write_raw(serverCtx, serverCtx->stage_data, serverCtx->stage_data_size); + + // to "hand over" the stage data, set the existing pointer to NULL so that things don't get freed + // when they shouldn't be. + serverCtx->stage_data = NULL; } // We need to generate a new session GUID and inform metasploit of the new session - GUID guid; - CoCreateGuid(&guid); + CoCreateGuid(&serverCtx->pivot_session_guid); + // swizzle the values around so that endianness isn't an issue before casting to a block of bytes - guid.Data1 = htonl(guid.Data1); - guid.Data2 = htons(guid.Data2); - guid.Data3 = htons(guid.Data3); + serverCtx->pivot_session_guid.Data1 = htonl(serverCtx->pivot_session_guid.Data1); + serverCtx->pivot_session_guid.Data2 = htons(serverCtx->pivot_session_guid.Data2); + serverCtx->pivot_session_guid.Data3 = htons(serverCtx->pivot_session_guid.Data3); Packet* notification = packet_create(PACKET_TLV_TYPE_REQUEST, "core_pivot_session_new"); - packet_add_tlv_raw(notification, TLV_TYPE_SESSION_GUID, (LPVOID)&guid, sizeof(guid)); + packet_add_tlv_raw(notification, TLV_TYPE_SESSION_GUID, (LPVOID)&serverCtx->pivot_session_guid, sizeof(serverCtx->pivot_session_guid)); packet_add_tlv_raw(notification, TLV_TYPE_PIVOT_ID, (LPVOID)&serverCtx->pivot_id, sizeof(serverCtx->pivot_id)); packet_transmit(serverCtx->remote, notification, NULL); PivotContext* pivotContext = (PivotContext*)calloc(1, sizeof(PivotContext)); pivotContext->state = serverCtx; pivotContext->packet_write = named_pipe_write_raw; - pivot_tree_add(serverCtx->remote->pivots, (LPBYTE)&guid, pivotContext); + pivot_tree_add(remote->pivot_sessions, (LPBYTE)&serverCtx->pivot_session_guid, pivotContext); } if (bytesProcessed > 0) @@ -602,6 +667,10 @@ DWORD request_core_pivot_add_named_pipe(Remote* remote, Packet* packet) if (dwResult == ERROR_SUCCESS) { dprintf("[NP-SERVER] request_net_named_pipe_server_channel_open. named pipe server %s", namedPipeName); + PivotContext* pivotCtx = (PivotContext*)calloc(1, sizeof(PivotContext)); + pivotCtx->state = ctx; + pivotCtx->remove = remove_listener; + pivot_tree_add(remote->pivot_listeners, pivotId, pivotCtx); } } while (0); diff --git a/c/meterpreter/source/server/win/server_transport_named_pipe.c b/c/meterpreter/source/server/win/server_transport_named_pipe.c index 1eb106e1..3dd2c24b 100755 --- a/c/meterpreter/source/server/win/server_transport_named_pipe.c +++ b/c/meterpreter/source/server/win/server_transport_named_pipe.c @@ -32,7 +32,7 @@ static DWORD server_pipe_poll(Remote* remote, long timeout) lock_acquire(remote->lock); - dprintf("[NP DISPATCH] testing for data on the pipe, making sure there's enough for a packet header"); + vdprintf("[NP DISPATCH] testing for data on the pipe, making sure there's enough for a packet header"); BOOL ready = PeekNamedPipe(ctx->pipe, NULL, 0, NULL, &bytesAvailable, NULL) && bytesAvailable >= sizeof(PacketHeader); DWORD result = GetLastError(); @@ -40,7 +40,7 @@ static DWORD server_pipe_poll(Remote* remote, long timeout) if (ready) { - dprintf("[NP DISPATCH] pipe data found %u bytes", bytesAvailable); + vdprintf("[NP DISPATCH] pipe data found %u bytes", bytesAvailable); result = ERROR_SUCCESS; } else @@ -48,7 +48,7 @@ static DWORD server_pipe_poll(Remote* remote, long timeout) if (result != ERROR_BROKEN_PIPE) { // simulate a wait so that we don't bash the crap out of the CPU? - dprintf("[NP DISPATCH] pipe data not found, sleeping (error %u)", GetLastError()); + vdprintf("[NP DISPATCH] pipe data not found, sleeping (error %u)", GetLastError()); Sleep(timeout); result = ERROR_NO_DATA; } @@ -175,9 +175,9 @@ static DWORD packet_receive_named_pipe(Remote *remote, Packet **packet) } payloadLength = ntohl(header.length) - sizeof(TlvHeader); - vdprintf("[PIPE] Payload length is %d", payloadLength); + dprintf("[PIPE] Payload length is %d", payloadLength); DWORD packetSize = sizeof(PacketHeader) + payloadLength; - vdprintf("[PIPE] total buffer size for the packet is %d", packetSize); + dprintf("[PIPE] total buffer size for the packet is %d", packetSize); payloadBytesLeft = payloadLength; // Allocate the payload @@ -199,6 +199,7 @@ static DWORD packet_receive_named_pipe(Remote *remote, Packet **packet) // Read the payload DWORD bytesAvailable = 0; + dprintf("[PIPE] Beginning read loop for a total of %u", payloadBytesLeft); while (payloadBytesLeft > 0) { dprintf("[PIPE] Trying to read %u (0x%x) bytes", payloadBytesLeft, payloadBytesLeft); diff --git a/c/meterpreter/source/server/win/server_transport_tcp.c b/c/meterpreter/source/server/win/server_transport_tcp.c index f7bd6b00..a7ed5104 100755 --- a/c/meterpreter/source/server/win/server_transport_tcp.c +++ b/c/meterpreter/source/server/win/server_transport_tcp.c @@ -475,7 +475,7 @@ static DWORD packet_receive(Remote *remote, Packet **packet) else { dprintf("[TCP] Session GUIDs don't match, looking for a pivot"); - PivotContext* pivotCtx = pivot_tree_find(remote->pivots, header.session_guid); + PivotContext* pivotCtx = pivot_tree_find(remote->pivot_sessions, header.session_guid); if (pivotCtx != NULL) { dprintf("[TCP] Pivot found, dispatching packet");