Entity tags as an HTTP covert channel
During a recent penetration test I was faced with an issue. I
obtained access to a network and needed to "smuggle" out a certain
binary file. However, DNS was not an option as resolution could only be performed on the HTTP proxies. In addition, we wished to avoid audit activitites taking place after the test identifying what data exactly travelled the network.
With HTTP Tunneling, this is usually difficult to achieve. Most of these tools perform tunneling either through a GET or POST request that contains the actual data in the URI request string. This means that after the fact, it is possible to identify what has been tunneled. The request string is often stored in proxy logs and can easily be retrieved.
In HTTP however, there is a certain interaction between the "Etag"
header (on the server side) and "Match-If-None" (and some related tags,
on the client side). Upon a connection, a server can provide an Etag, or
entity-tag, which is used by the client to identify the version it has
in its cache. Proxies can also put this field to use.
As is the case with e.g. basic authentication, these headers can be
lengthy and offer good performance in sending through data. More
importantly, the headers themselves are usually not logged. For the Etag
header, no particular format is described. It is merely a random value
contained by "" thatt identifies the entity and "may" be used for caching.
So, I put it to use a bit differently. I split up a file into small
groups of bytes and launched requests through the proxy with these parts
of the file (base64 encoded) as an Etag header. On the other end I had
an application running which received each of the Etags and stored them
to a file locally.
Naturally, the proxy would normally have cached my requests, if they were for one file, so I added a return "no-cache" header in the response. One disadvantage with this method is that in your proxy logs, you will have a high amount of GET requests with very little content. An example:
1148834194.664 258 10.0.0.1 TCP_MISS/200 64 GET
http://22.214.171.124/file.txt - DIRECT/126.96.36.199 -
1148834195.073 258 10.0.0.1 TCP_MISS/200 64 GET
http://188.8.131.52/file.txt - DIRECT/184.108.40.206 -
This is quite apparent even to the untrained eye. As such, I used the
"byte-range" header in the request so that they would be logged as 206
entries, and had the server create a random ASCII text file so that the
size of the transactions would be higher. This is a bit less obvious, as 206 means that a partial transfer is taking place - it could just be a client that's downloading a file in pieces.
Potential countermeasures that can be implemented:
For this purpose, I wrote a small piece of Perl code that could essentially get the job done. It is however not a software tool, as such don't expect it to work in all circumstances. It is called Wondjina.
- Implement stateful Etag checking on perimeter proxies. In general, an
If-None-Match should always match the previous Etag seen for a certain
entity. Nevertheless, as some hosts will have made the initial request
from the outside, the first Etag may not be available and will need to
be accepted at face value.
- Perform Etag inspection; in general, Etags have a format of
"4d008e-c87-43249525" for Apache servers. The Etags wondjina uses by
default are quite a bit larger to allow for quicker transfers. If speed is not a concern, nothing will stop you from fitting it into this type of header.
- Drop Etags and instead rely on the other caching mechanisms we have in
place. You could also use HTTP/1.0 requests which do not support Etags.
"In Aboriginal mythology, the Wondjina (or wandjina) were cloud and rain
spirits who, during the Dream time, painted their images (as humans but
without mouths) on cave walls. Their ghosts still exist in small ponds."
Do note that while in fact, Wondjina only tunnels out (one way traffic) the matching between Etag and if-none-match is ideal for bidirectional tunneling. Wondjina has a lot of limitations that depending on the situation you may require to run this succesfully:
If you'd like to give it a try, get wondjina here.
- In essence, if you send 10 different requests to a proxy, nothing guarantees that these will arrive in that order. If they don't, the file at the recipient side may be corrupted. This can be solved by implementing "protocol"; a set of rules known by both sides of the connection. In itself this will make it easier to detect the tunneling, but these can ofcourse be defined at both sites by the penetration tester to prevent this.
- Wondjinad just keeps on running and passively stores all incoming information. If you want to tunnel multiple files, you'd need to build in some type of "stop" code that both client and server recognize. Once again, this would mean implementing a protocol, with all advantages and disadvantages that come with it.
Read basic use instructions and documentation here.
Articles and discussions on HTTP tunneling
Securityfocus: Data driven attacks using HTTP tunneling
Devarticles.com: HTTP Tunneling revealed
Detecting HTTP Tunneling Activities
Links to HTTP tunneling tools and services
HTTPTunnel uses GET and POST for full socket tunnels
Hopster is commercial software for tunnling through HTTP proxies
HTun allows a TUN device to be tunneled
RFC 2616 - HyperText Transfer Protocol -- HTTP/1.1
ETag header support in the Squid proxy
A guide to understanding covert channel analysis of trusted systems [Light Pink Book]
Books that could be of help
HTTP Developer's Handbook