Category: Web Points: 75 Solves: 22 Description:
What does this service do? It hides a flag!
Navigating to the website, we see an input box and a query button. The first thing to do is throw some data at it and see what happens:
SENT: a RESPONSE: 61008ce2,CAMP15_silverneedle RESPONSE: 61010292,CAMP15_silverneedle SENT: ab RESPONSE: 61626b8f,CAMP15_silverneedle RESPONSE: 6162dc3f,CAMP15_silverneedle SENT: abc RESPONSE: not found
I initially verified using Burp Suite that the data coming back was what was expected. Indeed, the javascript on this page simply takes user input, sends it over the websocket, and prints whatever the server sends back. Also, based on a little playing around, it seems that not all combinations are valid.
My initial thought was to simply brute force the space with python using a depth first search. I used depth first because it clearly looked like there were not going to be long strings of requests that were valid:
#!/usr/bin/python3
from websocket import create_connection
import string
def isNeedle(s):
ws.send(s)
o = ws.recv()
if o == "not found":
return False
o2 = ws.recv()
if "CAMP15_silverneedle" not in o or "CAMP15_silverneedle" not in o2:
print("Golden Needle?: {0}".format(s))
exit()
return True
ws = create_connection("ws://challs.campctf.ccc.ac:10116/q")
def tryCombinations(b=""):
for c in string.printable:
print("trying {0}".format(b+c))
if isNeedle(b + c):
tryCombinations(b+c)
tryCombinations()
While the concept would work, I got tired of waiting and watching. Looking a little more closely at the responses, what we're getting back with a successful query are, at the minimum, the characters that we gave to the system in hex format. For instance, the first query of a came back as 61008ce2. Note that "0x61" is the ascii encoding for "a". With that in mind, the second question was why were we getting back two responses? My guess was that this was similar to a linked list, where the first number was possibly the closest value to whatever you put in, and the second was the next number in the list. If true, this would allow us to walk down the linked list until we found the golden needle.
#!/usr/bin/python3
from websocket import create_connection
import string
from binascii import unhexlify
def followNeedles(s=b'\x94\xe2\xdf!'):
while True:
ws.send(s)
print("Trying: {0}".format(s))
o = ws.recv()
if o == "not found":
print("Not found error...")
return False
o2 = ws.recv()
#print("{0} valid".format(s))
if "CAMP15_silverneedle" not in o or "CAMP15_silverneedle" not in o2:
print("Golden Needle?: {0}\n{1}\n{2}\n".format(s,o,o2))
exit()
s = unhexlify(o2.split(",")[0])
ws = create_connection("ws://challs.campctf.ccc.ac:10116/q")
followNeedles()
It was indeed true. After a little while of waiting, we found:
Trying: b'\x94\xe2\xdf!'
Golden Needle?: b'\x94\xe2\xdf!'
94e2df21,CAMP15_foobar_golden
94e44d19,CAMP15_silverneedle
Flag: CAMP15_foobar_golden