hackTM2020 ananas writeup
We are given a ananas.pcapng packet capture and a hint that a camera/video is involved…
1. obtaining a binary
this looks like a windows binary, so we save the binary into ananas.exe
> file ananas.exe
ananas.exe: PE32 executable (console) Intel 80386 (stripped to external PDB), for MS Windows
and indeed, it is a windows executable binary.
2. static analysis of ananas.exe
After some analysis in IDA, we note that there are some send and recv operations involved and also some frame grabber code used for capturing a 90×160 sized images.
– 90×160 = 14400 pixel are grabbed in grab_pixels
– they are converted into grayscale, resulting in an array of 14400 bytes
lets examine the obfuscate_and_send() function:
So it seems that the following steps take place for each frame of size 90×160:
- 14400 pixels grayscale are grabbed
- a 4 bytes ‘key’ is received from a peer
- this ‘key’ is used in (next_index() % i) to derive an index to be swapped
- the current pixel is swapped with whatever index is obtained in step 3
- the obfuscated grayscale data is sent over the socket
Lets see if this make sense in the remainder of the packet capture:
We see:
1. 4 bytes are sent from 134.209.225.118. This matches the key bytes
2. a payload of 14120 bytes is sent to 134.209.225.118
3. a payload of 280 bytes is sent to 134.209.225.118
so, we receive 4 bytes and send out 14400 bytes. This matches our static analysis
In order to retrieve the grayscale frames we need to:
- extract each 14400 bytes payload
- extract the corresponding 4 bytes key
- perform a deobfuscation of the payload
3. Extracting payload frames and keys
we used scapy in order to dump each key into a keyfile_X and each 14440 bytes into a packet_X files:
from scapy.all import *
with PcapReader("ananas.pcapng") as pcap_reader:
for pkt in pcap_reader:
if pkt.haslayer(TCP) and pkt[TCP].sport == 18812 and pkt[TCP].flags == "PA":
open("keyfile_%d" % index, "wb").write(pkt[Raw].load)
elif pkt.haslayer(TCP) and pkt[TCP].dport == 18812 and pkt[TCP].flags == "A" and pkt.haslayer(Raw) and len(pkt[Raw].load) == 14120:
packet_data = pkt[Raw].load
elif pkt.haslayer(TCP) and pkt[TCP].dport == 18812 and pkt[TCP].flags == "PA" and pkt.haslayer(Raw) and len(pkt[Raw].load) == 280:
packet_data += pkt[Raw].load
open("packet_%d" % index, "wb").write(packet_data)
packet_data = b""
index += 1
4. Deobfuscating the packets
when we examine the next_index() function, it is clear that for each initial key, the sequence of the resulting 14399 swap indices can be inferred
by running the next_index() on that initial key and collecting the indices.
Given those 14399 index-pairs, how do we reverse the obfuscation?
Let’s try an example. Assume we apply the following sequence of swaps, in that order:
(0, 30) //pixel[0] is swapped with pixel[30]
(30, 70) // pixel[30] (aka pixel[0]) is swapped with pixel[70]
this results in:
pixel[0] ended up in pixel_obf[70]
pixel[30] ended up in pixel_obf[0]
pixel[70] ended up in pixel_obf[30]
now, if we apply the swaps in reverse from the last one, we get:
(30, 70)
(0, 30)
pixel_obf[70] ended up in pixel[0]
pixel_obf[0] ended up in pixel[30]
pixel_obf[30] ended up in pixel[70]
which is exactly the original order!
The following C code opens keyfile and packet.obf, uses the key to generate and collect 14399 index swaps and then applies the swaps in the reverse order:
#define BUFSIZE 14400
int main(int argc, char** argv) {
int inkeyfd = open(argv[1], O_RDWR); // keyfile
int infd = open(argv[2], O_RDWR); //packet.obf
int outfd = open(argv[3], O_RDWR | O_CREAT, 0666); //packet.deobf
char buffer[BUFSIZE];
read(inkeyfd, buffer, 4);
key = *(unsigned int*)buffer;
printf("key: %x\n", key);
read(infd, buffer, BUFSIZE);
int swaps[BUFSIZE][2];
for (int i = BUFSIZE - 1 ; i > 0; --i) {
int v7 = ((unsigned short)next_index()) % i;
swaps[i][0] = i;
swaps[i][1] = v7;
}
for(int i = 1; i < BUFSIZE; ++i) {
char v6 = buffer[swaps[i][1]];
buffer[swaps[i][1]] = buffer[swaps[i][0]];
buffer[swaps[i][0]] = v6;
}
write(outfd, buffer, BUFSIZE);
return 0;
}
running the above C code on each packet_X file produces a de-obfuscated file packet_X.deobf which we can convert into a png image and combine all images into an animated gif.
this produces a short film of a guy showing us the flag on his phone.