33c3 CTF just finished. And here’s the writeup for the highest point value challenge I could get. It wasn’t too complicated and as echoed by some of my team mates, I think the point values were a little unbalanced for this CTF. Nonetheless, the challenges were difficult and exciting. Thanks to the 33c3 CTF Team for hosting another great CTF.

yoso - 250

You only live once, so why search twice?

(admins love to search for flags btw)

Part 1 - Recon - VoteForMe XSS

Starting with the pretty home page. We have a lot of links here.


After logging in, we can now ‘research’ things. I.e. search things and then have them saved to our bookmarks. Nothing interesting.


Bookmarks lets you view your bookmarks. You can also backup your bookmarks into a zip with a password.


The download.php page (where the backup function leads) has some interesting reflected variables. This is our XSS vector for later


And we have our XSS contact form which asks for interesting links.


Part 2 - Exploitation - One stop XSS

We could obviously send the bot a link to our page, but that wouldn’t help us exfil information, since we’d be bashing our heads against SOP (Same Origin Policy), and DNS rebinding to bypass SOP is not fun. So we need to find some XSS on the website so we can exfil whatever the contents on the bookmarks page is. (as per the hint).


Standard testing XSS. from our reflected download.php page. Looks like we’re cooking with fire


Unfortunately, if we try a URL, it seems to strip all dots from our input.


The workaround is to use a decimal IP address with no dots. Also, given that <script> will try and execute whatever it is as javascript, we dont need to worry about file extension.

so with some payload like (with an obviously changed IP address to not mine)

Now we have an XSS page, we need some scripts. Since this page is barebones, there’s no jQuery, and all my scripts are lazy and use jQuery… so I cheated and pasted jQuery.min at the top of the file. (don’t hurt me please, their ajax is nice).

<snipped jquery.min for sanity>
$.ajax({ method:"GET",
    xhrFields: {
            withCredentials: true
    success: function(resp) {
                success: resp
    error: function(data) {

Have your listener server running. and…


Flags on the page. Woohoo!



At first I thought it was a bit more complicated, where you had to exfil the bookmarks zip. This would’ve been a lot harder since you would have had to XSS to get the CSRF token then use that to post and create a new bookmark zip. Thankfully the result was on the page already saving me some braincells.