Uninformed: Informative Information for the Uninformed

Vol 1» 2005.May


HTTP Tunneling ActiveX Control

The second stage is arbitrary in that an attacker could implement an ActiveX control to do virtually anything. For instance, an ActiveX control could cause a chicken wearing pants to slide around the screen every few minutes. Though this would be patently useless, it's nonetheless an example of the types of things that can be accomplished by an ActiveX control. For the purposes of this document, however, the ActiveX control will construct a communication channel, over HTTP, between a target machine and the attacker's machine such that arbitrary data can pass between the two entities in a way that is compatible with restrictive outbound filters. Like the payload described in [*], there are a number of ways to implement an ActiveX control capable of accomplishing this task. Going forward, this section requires basic knowledge of COM (Component Object Model)[6].

The approach taken in this document was to create an ActiveX control using ATL, short for Active Template Library)3.6. The purpose of the ActiveX control, as described in this chapter, is to build an HTTP tunnel between the attacker and the target machine. The ActiveX control should also be able to, either directly or indirectly, make use of the HTTP tunnel, such as by piping the input and output of a command interpreter through the HTTP tunnel.

The ActiveX control discussed in this document makes use of the HTTP tunnel by creating what has been dubbed a local TCP abstraction. This is basically a fancy term for using a truly streaming connection, such as a TCP connection, as an abstraction to the bidirectional HTTP tunnel. The reason this is advantageous is because it allows code to run without knowing that it is actually passing through an HTTP tunnel, hence the abstraction. This is especially important when it comes to re-using code that is natively capable of communicating over a streaming connection.

One way in which this abstraction layer can be created is by having the ActiveX control create a TCP listener on a random local port. After that, the ActiveX control can establish a connection to the listener. This creates the client half of the streaming connection which will be used to transmit data to and from the remote machine in a truly streaming fashion. After the ActiveX control establishes a connection to the local TCP listener, it must also accept the connection on behalf of the listener. The server half of the connection is what is used both to encapsulate data coming from the target machine to the attacker's machine and as the truly streaming destination for data being sent from the attacker to the target machine. Data that is written to the server half of the connection will, in turn, be read from the client half of the connection by whatever it is that's making use of the socket, such as a command interpreter. This method of TCP abstraction even works under the radar of application-based filters like Zone Alarm because the listener is bound to a local interface instead of an actual interface3.7.

The ActiveX control itself is composed of a number of different files whose purposes are described below:

File Description
CPassiveX.cpp Coclass implementation source
CPassiveX.h Coclass implementation header
HttpTunnel.h HTTP tunnel management class header
HttpTunnel.cpp HTTP tunnel management class source
PassiveX.bin Interface registration data
PassiveX.idl IPassiveX interface, coclass, and typelib definition
PassiveX.rc Resource script containing version information, etc
resource.h Resource identifier definitions
PassiveX.cpp DLL exports and entry point implementations

The first place to start when implementing an ActiveX control is with the control's interface definition which is defined in PassiveX.idl. In this case, the control has its own interface defined so that it can export a few getters and setters that will allow the browser to set properties on an instance of the ActiveX control. The ActiveX control requires two primary parameters, namely the attacker's remote host and port, in order to construct the HTTP tunnel. Furthermore, it may also be necessary to instruct the ActiveX control that it should download more custom code to execute once the control has been initialized, such as a second stage payload that would make use of the established HTTP tunnel. Parameters are typically passed using the HTML PARAM tag in the context of an OBJECT tag.

The three parameters that the ActiveX control in this document supports are:

Property Description
HttpHost The DNS or IP address of the attacker controlled machine
HttpPort The port, most likely 80, that the attacker is listening on
DownloadSecondStage A boolean value which indicates whether or not a second stage should be downloaded

The getters and setters for these three properties are provided through the control's IPassiveX interface which is defined in the PassiveX.idl file. The coclass, defined as CPassiveX in CPassiveX.h, uses the IPassiveX interface as its default interface. Aside from the default interface, the ActiveX control must also inherit from and implement a number of other interfaces in order to make it possible for the ActiveX control to be loaded in Internet Explorer3.8.

Once the ActiveX control's interface and coclass have been sufficiently implemented to allow an instance to load in the context of Internet Explorer, the next step becomes the constructing of the HTTP tunnel. One of the easiest ways to implement this portion of the ActiveX control is to make use of Microsoft's Windows Internet API, or WinINet for short. The purpose of WinINet is to provide applications with an abstract interface to protocols such as Gopher, FTP, and HTTP[7]. One of the major benefits to using this API is that it will make use of the same settings that Internet Explorer uses as far as proxying and zone restrictions are concerned. This means that if a user normally has to send their HTTP traffic through a proxy and has configured Internet Explorer to do so, any application that uses WinINet will be able to share the same settings3.9. The actual API routines that are necessary to build an HTTP tunnel using WinINet are described below:

WinINet Function Purpose
InternetOpen Initializes the use of the other WinINet functions
InternetConnect Opens a connection to a host for a given service
InternetSetOption Allows for setting options on the connection, such as request timeout
HttpOpenRequest Opens a request handle that is associated with a specific request
HttpSendRequest Transmits an HTTP request to the target host
InternetReadFile Reads response data after a request has been sent
HttpQueryInfo Allows for querying information about an HTTP response, such as status code
InternetCloseHandle Closes a WinINet handles

The above described functions can be used to create a logical HTTP tunnel that conforms to the HTTP protocol, appears like a normal web-browser, and uses any pre-configured internet settings. The basic steps necessary to make this happen are described below:

  1. Initialize WinINet with InternetOpen

    In order to make it possible to use the facilities provided by the Windows Internet API, it is first necessary to call wininet!InternetOpenA. The handle returned from a successful call to wininet!InternetOpenA is required to be passed as context to a number of other routines.

  2. Create the send and receive threads

    Since there are two distinct channels by which data is transmitted and received through the HTTP tunnel, it is necessary to create two threads for handling both the send and the receive data. The reason these two channels cannot be processed in the same thread efficiently is because one half, the local TCP abstraction half, uses Windows Sockets, whereas the second half, where data is read in from the contents of HTTP responses between the target machine and the attacker machine, uses the Windows Internet API. The handles used by the two APIs cannot be waited on by a common routine. This fact makes it more efficient to give each portion of the communication its own thread so that they can use the native API routines to poll for new data.

  3. Poll the server side of the TCP abstraction in the send thread

    In order to check for data being sent from the target machine to the attacker's machine, it is necessary to poll the server side of the TCP abstraction. This can be accomplished by calling ws2_32!select on an fd_set that contains the server half of the connection that was established to the local TCP listener. When ws2_32!select returns one it indicates that there is data of some form available for processing, whether it be actual data to be read from the socket or an indication that the socket has closed. When this occurs a call to ws2_32!recv can be made to read data from the socket. If zero is returned it indicates that the local connection has been terminated. Otherwise, if a value larger than zero is returned, it indicates the number of bytes actually read from the connection. The buffer that the data was read into can then be used as the body content of an HTTP POST request that is transmitted to the attacker. This cycle repeats itself until the local connection eventually closes, an error is encountered, or the stateless tunnel between the two endpoints is terminated.

  4. Poll for data from the remote side of the of the HTTP tunnel in the receive thread

    Polling for data that is being sent from the attacker to the target machine is not as simple the other direction simply due to the fact that the polling operation must be simulated using an HTTP GET or POST request instead of using a native routine to check for new data. This approach is necessary in order to remain compliant with HTTP's request/response format. The actual implementation is as simple as an infinite loop that continually transmits an HTTP request to the attacker requesting data that should be written to the server side of the TCP abstraction. If data is present, the attacker will send an HTTP response that contains the data to be written in the body of the response. If no data is present, the attacker can either wait for data to become available or respond with no content in the response. In either case, the polling thread should repeat itself at certain intervals (or immediately if data was just indicated) for the duration of time that the stateless HTTP tunnel between the two endpoints stays up.

Beyond these simple tasks, the ActiveX control can also download and execute a second stage payload in the context of its own thread. This second stage payload could be passed the file descriptor of the client half of the TCP abstraction which would allow it to communicate with the attacker over a truly streaming socket that just so happens to be getting encapsulated and decapsulated in HTTP requests and responses. There are also a number of other things that could be developed into the ActiveX control to make it a more robust platform from which further attacks could be mounted. These extensions will be discussed more in the next chapter.