This weekend, I participated in the SHA2017 CTF. I was able to solve one challenge in the time available, then was able to solve a second, but unfortunately too late to score anything. The writeups are presented below.
The “asby” challenge was presented as a Windows binary file, which you can download here. A hint was provided – that we could “asby” the flag out.
Upon initial inspection, we quickly notice an interesting string usage, which indicates a sequential check against the flag:
I immediately applied the principle of “brute force, best force” against the application’s stdout, but trickery was afoot: that is, a brute-force search would indicate that “0” was the correct first character of the flag, but upon manually checking with a flag of “01”, the program indicated that “0” was not the correct first character.
We then inspect the logical flow of the application. We can use IDA’s graph mode to identify what appears to be a character check:
Following the disassembly backwards, we note that a character is loaded at 0x40179d, an “xor key” seems to be loaded at 0x401789 (the source of “ecx” in the above). The two characters are xor’ed together, then xor’ed with 0x2a, and compared with a value in al.
We can use windbg to inspect the state of the executable, breaking at the above two addresses and inspecting the strings loaded:
We then break at the final address of 0x4017A7, to identify what’s being compared against what:
Following the disassembly backwards, we can see that al comes from the the first character of the two loaded strings above xor’ed together, then xor’ed together with 0x2a, where 0x4B is the first character of our input (“a_123”) xor’ed with 0x2a.
We then build a quick python script to take the two strings above, xor them together and xor them with 0x2a, which you can download here.
Unfortunately, this only brings us a part of the flag:
At this point, I wondered if an initial “failsafe” check had been put in place, to prevent naive brute forcing, but if this would remain untouched if we provided a part of the correct key. I modified my original brute force script to include the first part of the correct key, and to create a new process for each brute force attempt, as I knew that a maximum of 100/115 tries was permitted before the process died – this revealed the flag in short order:
You can download the final Python script here.
Abuse Mail (Late Writeup)
The “Abuse Mail” challenge was presented as a zip file containing three packet captures, which you can download here.
Our initial inspection reveals “abuse01.pcap” to contain some telnet data followed by an ipsec connection, while the other pcaps contain some manner of data encoded within ICMP ping packets. We begin our analysis by recovering the ipsec tunnel keys, to allow us to decode the ipsec tunnel. We can get this from the telnet session:
This reveals the ipsec tunnel to be hiding an HTTP connection. Browsing the connection stream reveals the installation of a backdoor in /tmp/backdoor.py. Fortunately, the full file is provided in the IPSec tunnel:
as well as the command line used to launch it (revealing the AES key):
From here, we can easily reverse engineer the backdoor script to allow us to decode the streams encoded in the “abuse02.pcap” and “abuse03.pcap” packets. Here, I took two shortcuts – firstly, as the data was encoded as a string, I simply ran strings across the pcaps and filtered for “SHA2017”. Secondly, I did some “duct tape debugging”: I simply tried trial and error with base64 padding when I couldn’t decode a packet, instead of attempting to understand the protocol and it’s hazards fully.
You can download this decoder here.
We start off by decoding abuse02.pcap, which you can download here. We immediately note the presence of a private key, and save it:
Finding little else of significant interest, we proceed to abuse03.pcap, which appears to be responses to the “getfile” command. My initial attempt at decoding this file met with failure, as I simply pasted the data chunks in chronological order. Going back to the original Python backdoor, we note that each “getfile” chunk comes in the following form:
Where “cnt” was an incremental counter. We note that some “cnt” files are repeated, so we seperate them out into two seperate pcap files (I actually got here by happy accident – I initally just filled an array with chunks, keyed to the “cnt” field – this generated one of these files, but with extra data at the end, leading to the second). The first file is a USB packet capture:
We know from the USB descriptor (and Google’s boundless wisdom) that this is infact a HID keyboard. The actual “keypress” data is stored in URB_INTERRUPT packets, as follows:
We can use “tshark” to spit out the capture data from URB_INTERRUPT packets (or rather, the packets with extra capturedata, corresponding to our keystroke packets) as follows:
tshark -r out.pcap -T fields -e usb.capdata
Taking the output from this, we can refer to the USB HID standard, and map these packets to actual keystrokes. A quick Python script does the job, which you can download here. The keys typed are as follows:
The carat characters represent the shift key, so the unzip password in this case is “Pyj4m4P4rtY@2017”.
We then return to the other file which we were able to extract from abuse03.pcap, which is a TLS-encoded stream. Using the private key we were able to recover earlier, we can then save “secret.zip” from the stream:
Decoding it with the password captured from the USB packet capture reveals the flag:
As always, thanks to the SHA2017 CTF organisers for putting together a fun and challenging event – I was not expecting a 300-point challenge to be this in-depth.
See you all in the HackIT CTF in two weeks time!