[SECCON 2019] — Writeup

Nicholas Rianto Putra
Oct 20 · 7 min read

Writeup for SECCON 2019 Quals by Bat Family.

SECCON 2019 Quals

Here we will explain our solution for some challenges on this year SECCON Qualifier.

Table Of Contents

Web: SPA — 427 points
Web: fileserver — 345 points
Web: web_search — 212 points
Web: Option-Cmd-U — 190 points
Crypto: ZKPay — 308 points


Web: SPA — 427 points

Last day my colleague taught me the concept of the Single-Page Application, which seems to be the good point to kickstart my web application development. Well, now it turned out to be MARVELOUS!
http://spa.chal.seccon.jp:18364/
Steal the cookie.

On this challenge, we were given a Vue Single Page Application. As the description said, there is a feature of report admin where we could submit our payload to steal the admin cookie.

Report Admin Feature

We try to click the menu, and the website will display the flag of the previous SECCON Quals.

Display of the Website

Below is the Vue code that fetching the JSON data.

Snippet of the fetchContests() function

After reading through the Vue Code, we figure out that when we click the menu (for example: SECCON2014), the URL will be change to “/#SECCON2014”. After that, everything after the “#” symbol will be set as the contestId, and the web will try to load SECCON2014.json in order to retrieve the data and display it.

Notice that we could control the contestId parameters. We setup a server to create an endpoint that could return a JSON data to check whether the website could load the data from external site or not. Using beeceptor, we try to load it and our prediction is true.

Our mock API
IT WORKZZZ

After finding that we could load data from external site, we try to read the documentation of method to look for a vulnerability. We found an interesting information from the documentation that said

JSONP
If the URL includes the string “callback=?” (or similar, as defined by the server-side API), the request is treated as JSONP instead. See the discussion of the data type in for more details.

Refering to this article, We could use JSONP to craft our XSS Payload because will use a script tag injection to attempt a JSONP call. First, we create our mock API with endpoint contains and we just need to return a javascript code on our response.

Testing mock API that will invoke alert(1)

Let’s try to access

EZ XSS

Yeay, we invoke an XSS. Because we need to steal admin cookie, we just need to craft our response of the mock API into . Send the above URL to the admin, and the admin will visit our endpoint with the flag.

REPORT!!
FLAGGGGGGGG

Web: fileserver — 345 points

I donno apache or nginx things well, I guess I can implement one for myself though. See? It’s easy!
http://fileserver.chal.seccon.jp:9292/public/index.html
Due to maintainability, we restart the server of fileserver challenge every 5 minutes.

We try to visit the website, and turn out it is a Ruby Webrick server. Testing a little bit Directory Traversal, we could access to get list of available files on the website directory. We try to download all the files.

Server Code app.rb

Reading through the server code, it is obvious that we could do directory traversal to leak the flag filename (if we could bypass all the annoying filters). If our path end with the server will return the list of files on that directory. However, we couldn’t use because it got filtered. In order to leak the directory traversal, we try to inject on our path. Turn out, it works! We found the flag names on folder.

Flag filename

Now here is the tricky part. In order to read a file, our path couldn’t end with char. But, webrick doesn’t allow us to use to navigate to the flag directory. After reading for a while, we found a bug on the is_bad_path function.

Notice that if the function detect a or , it will break the search and return False if there isn’t any pair of that bracket. If our path contains , the is_bad_path will return False instead True, because when it detects the square bracket, it breaks the search for other prohibited symbol, and will return False if there isn’t any square bracket even though we have a pair of curly braces. Leveraging this bug, we could use Shell Globbing to navigate into our flag directory and read it. Final Payload:

FLAGGG

Web: web_search — 212 points

Get a hidden message! Let’s find a hidden message using the search system on the site. http://web-search.chal.seccon.jp/

A classic SQL Injection. Trying some payload, we realize that they filter . Instead using spaces, we could use or . To bypass the filter of , we could use because it will delete the in middle and will lead to another .

The website already give use the first part of the flag if we put , and give us information that we need to leak table . So now, we need to leak the number of columns first. Using , we could found out that thee total of columns is three. After that, we just need to change one of the UNION table join (let say ) into to get the second part. Don’t forget to change into .

Final Payload for first part:
Final Payload for second part:

First part
Second Part

Web: Option-Cmd-U — 190 points

No more “View Page Source”!
http://ocu.chal.seccon.jp:10000/index.php

We could access the source code on here . Reading through the source code, we found the source code of the allowed URL filtering.

Source Code

Reading through the source coded, we need to start our url with . We have bypass the first check, now we need to bypass the second check that didn’t allow us to access nginx. Using Unicode of slash (), we could bypass the second if. We have bypass all the check and we could load .

FLAGGGGG

Crypto: ZKPay — 345 points

http://153.120.18.131/

Trying to signup, turn out that we need to have deposit larger than 1000000 dollar to see the flag. We try to use the send money feature, which is generating a QR Code that could be decoded using the receive money feature. We try to generate two QR Code with different amount, and then try to decode the QR Code. The QR Code will be decoded to a string like URL params. The example decoded content:

Trying to change the amount and generate a new QRCode, turn out that the decoded content has the same proof params. We try to change the amount to negative integer (-1000000), generate a new QRCode, create a new user, redeem the QRCode, and our current money got increased above 1000000.

Generate new QR Code with amount negative
Redeem it on another account, the other account will have negative deposit
Our main account deposit got above 1million :D

HMIF ITB Tech

HMIF ITB Tech Blog

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade