Blog of Malte Kraus


ccauthd write-up: UCSB iCTF 2014

19 Apr 2015

So last week UCSB organized another iCTF, crazy as always. This time, they reused 42 services from older iCTFs. Some were modified so that copy-pasting exploits from write-ups didn't work, some were not. Some others were old enough that there just are no write-ups on the internet. A lot of write-ups were apparently taken down during the competition, or (by UCSB) right before it. The Internet Archive saved the day here.

Since there is no point in repeating the old write-ups I used to exploit some of the newer services this blog post will focus on ccauthd which was completely unknown to the internet at the day of the competition and still doesn't seem to have a write-up. Although I just now found what seems to be the source code. It looked a bit weirder in IDA, but not too much.

The service has a text interface usable over telnet or netcat. It allows registering a string, which stores that string and returns a secret auth token that can be used later to retrieve the stored string. This is implemented by creating a file named like the auth token that contains the registered string.

Like in earlier years, UCSB ran uploaded exploits on their own hardware. Other team's vulnboxes were not reachable directly. In the case of ccauthd, the exploit script got the first 14 characters of the auth token and was supposed to return the string stored under the full 31 character token.

The first issue we found in the service was related to the generation of auth tokens during registration, which is done using rand(3). At program startup, the random number generator is initialized by the current time: srand(time(0)). At that time the game server had stored less than 100 flags and the game had run only for a few hours. So this was clearly in brute-force territory. So I wrote a simple script that for every second since the CTF had started (where the service could potentially been started) generated 100 possible auth tokens until one matched the 14 given characters. This worked great locally and I'm sure it'd have worked great against 90% of the other teams, but sadly it never got that far because exploit scripts are first tested against an unpatched vulnbox by UCSB which was apparently started way earlier, making brute-force unfeasible.

On our own machine, we 'fixed' this by loading a library with LD_PRELOAD that modified rand(3) to get its data from /dev/urandom.

After this let-down we went back to the service, looking for the intended vulnerability. Kind of embarrassingly, we only found it by looking at the traffic of other teams exploiting us. While the authentication command appears to check the given auth token is all alpha numeric and a file by the same name really exists, it actually does so only for the first 32 characters. It then used all input to construct a shell command for system(3) that retrieved the flag. We could basically just copy the exploit that was used against us, in order to fix it I modified the loop checking that the auth token is alpha-numeric to check the whole length of the buffer. This meant an attacker had a chance to overflow the id array, but only into a buffer next to it that already contained attacker-controlled input.

Later on, we tried to combine both exploits (the second one to get past the correctness check, and the first one to get tht flags), but at that point the CTF already ran for over 6 hours and our server had generated a bit less than 400 flags, which again made brute-force impossible in the few seconds the exploit script had until it was killed.