SpiderLabs Blog

Hidden Data Exfiltration Using Time, Literally

Written by Tom Neaves | Oct 17, 2023 1:00:00 PM

 

I was looking at my watch last week and my attention was moved towards the seconds over at the right of the watch face, incrementing nicely along as you’d expect. Now, I don’t know if I’d just spent too long staring at a debugger screen or if it was something in the air, but an idea dawned on me, related to all things command and control, data exfiltration, etc. When I saw “41,” I saw “A,” which is the hexadecimal representation for it, “42” being “B” and so on – a lot of pentesters will relate. You know what... I theorised, these seconds of the time could be used to represent data, in a form we already have, ASCII.

 So, I did what any other pentester would do and opened up nano and started writing some python code to serve as a proof of concept to see if this thing could actually work outside of my head, in reality.

 

 I translated this proof of concept over to a common occurrence on the Internet where time is communicated to a client as part of a normal response, and that is in HTTP, by a web server.

 

 Figure 1. A typical HTTP request and response, with a HTTP ”Date” header in the response

 

As part of HTTP, upon receiving a request from a client, a normal web server will, in the HTTP response headers, provide a “Date” value, in the format of:

 

 Figure 2. HTTP “Date” header up close

 

As a client, if you made 10 HTTP requests, one every second, you’d have 10 corresponding responses from the server, each with a set of HTTP headers, with the “Date” value varying between them like so:

 

Figure 3. A collection of “Date” values taken from 10 sequential HTTP Responses

 

You’d also expect for the hours, minutes, and seconds (the latter in this example of 10) to rightly increase, unless you were sitting next to Doc Brown in his DeLorean.

 

 Has anyone ever taken any notice of this “Date” value? Probably not… I know as a pentester I’m swayed into focusing my attention on the data in the response body. I will look at the HTTP headers of course, but the “Date” header, not really interesting to me from a security perspective… it is often the wrong hour with time zone differences anyway. In summary, it often gets ignored.

 

 This is why I wanted to write this blog post, to indicate that we shouldn’t be ignoring seemingly non-interesting values (such as time), especially from a threat hunting perspective. I wanted to demonstrate that time itself (used here in the “Date” HTTP header) can be used to represent data and can be used as a hidden data exfiltration channel.

 

The proof of concept is as follows.

 

There is a ‘web server’ (air quotes with those fingers) sitting on the Internet, displaying the default Apache web server page of “It Works!” when a page is requested by a user. It appears like it is a default install of Apache, nothing really to see here. It returns “HTTP/1.1 200 OK” and a bunch of HTTP headers (such as “Date”) in the response. It looks like a web server. Obviously it is not Apache, this is instead my python socket code goodness emulating it.

 

There is a file on the web server in /goodness/spiderlabs.txt containing a secret code. I think you can see where this is going? Strap in.

 

Now, make two HTTP requests, one per second. Let’s look at the HTTP “Date” header value returned in the responses.

 

Figure 4. 2 “Date” header values extracted from 2 sequential HTTP Responses

 

That’s weird, we seem to have jumped 20 seconds. Make two more HTTP requests, one per second.

 

Figure 5. Another 2 “Date” header values

 

The first one was ok, the second one however, that jumped 10 seconds. Strange.

 

Let’s make two more requests, just to be sure.

 

Figure 6. 2 More “Date” header values

 

Yeah, time… about that. I think you will agree with me that the above doesn’t look too out of place unless you’re paying attention to it in the first place, and that you’re comparing it with what went before so you get the context. This is really the beauty of it and how it allows it to be hidden.

 

Let me explain what is going on ‘under the hood’ with my proof of concept.

 

Remember this isn’t a real web server, but it acts like one, so everything works the same with regards to the user/browser, etc. Because I’ve constructed it from scratch, I get to manipulate everything, namely the “Date” value in the HTTP header. The hours and minutes are allowed to go on as nature intended them, they will increment as normal, as per the system time. The seconds field however, no, this bad boy we’ll be utilising to channel the data.

 

With each request made to the web server, it will open /goodness/spiderlabs.txt and will read out a character, returning the ASCII representation of it in the seconds value. It will repeat this on each new request, sliding over to the next character in the file. For example, uppercase “A” is “65” in ASCII, lowercase “a” is “97,” etc. We have a slight problem though, ASCII runs from 0 through to 127 whereas our key space is about half of that at 60, because there are 60 seconds in a minute. I know not many people pay attention to the “Date” HTTP header but something like “97” (to represent “a”) in the seconds field is going to really stick out because logically it doesn’t make sense.

 

Figure 7. “97” really sticks out in the seconds field

 

You don’t have to understand what went before or context to know this isn’t right… as long as you have knowledge that there are only 60 seconds in a minute then having “97” in the seconds bit would raise eyebrows.

 

So I came up with the solution to chop the number 64 from the ASCII value returned to give us a smaller number. I decided that I wanted uppercase and lowercase letters and sacrificed numbers and some other useful characters. This is fine as it is a proof of concept, but if certain characters were important to me I’d shift/adjust what I did to the number to get it into the limited key space of 60. Why 64 I hear you ask? Because “A” starts at number 65 and if we take 64 away we get to 1. I append a zero and turn this into “01” when placing it back into the “Date” header so it matches the format and doesn’t look out of place. On the end of the characters we’re using, “z” we turn into 122 and then take 64 from it to make it 58, which fits into the key space still.

 

This is messy I know, but, as long as we’re doing it the other end (reversing the process) so we add 64 back to the numbers received, we’re good.

 

If we take the values from earlier:

 

Figure 8. All the “Date” values from the previous 6 HTTP Responses

 

…and we do some Maths:

 

20 + 64 = 84 = T

40 + 64 = 104 = h

41 + 64 = 105 = i

51 + 64 = 115 = s

31 + 64 = 95 = _

41 + 64 = 105 = i

 

The secret code so far: This_i

 

As you can see, I sacrificed the <space> character but not a problem, we can be creative and use some bonus characters such as _ instead.

 

Let’s bust out Burp (Intruder), to automate this from the client side, to make a request each second, extract the seconds from the “Date” header and save to a file.

 

Figure 9. Burp (Intruder) making one request per second and in the response extracting the seconds value from the “Date” HTTP header in the column to the right

 

We’ll then do the post processing (add 64) and then get the ASCII representation back.

 

Figure 10. Python magic looping through each of the ‘seconds’, adding 64 to them and getting the ASCII representation back

 

The contents of /goodness/spiderlabs.txt is, as channelled through the “Date” HTTP header:

 

This_is_a_secret_code

 

Hopefully my proof of concept conveys the importance of looking at these seemingly uninteresting areas, looking at them both in context and in comparison to what has come before and after, to work out if what is being returned seems logical. This could apply to other instances of course.

 

I’m not going to release any code because the intention of this post was one to raise awareness and highlight.

 

As always, thanks for reading!