Tripwire’s Vulnerability and Exposure Research Team (VERT) set up a three and a half day Capture the Flag (CTF) contest, where over 100 people from the academic community (mostly students, but more generally, people “affiliated with an educational institution”) competed in exploiting two vulnerable web applications.
The idea of a CTF is that there are hidden “flags” (which can be links, passwords, comments, etc.) that are not accessible directly through the application, but which can be discovered through “hacking.” CTFs, unlike wargames – which I have played in the past – are competitive, and as a result involve rewards.
Come the day of the competition, I had already set up Burp, so that I could intercept and alter HTTP(S) requests and responses, and eagerly awaited for the email with the details to come. This is the story of how I completed the challenges and placed second in the competition.
The link provided to us was https://ctf.secur3.us/, which had an invalid certificate, but could also be accessed over HTTP (Note that this link, and likely all other CTF links, might no longer work when you are reading this but I kept them intact for this writeup.) The link was an application that contained a “guestbook,” where people could leave and view messages.
The form (shown below) and the guestbook entries (not shown) had three fields: name, handle, and comment.
The two things to test for immediately are CrossSite Scripting (XSS) and SQL injection. The former doesn’t work, but leaving single quotes in the three fields results in an error page redirecting to the guestbook. If you are quick enough to stop the redirection, a suspicious value appears in the source code:
<img src=/images/fail.jpg ALT=SU5TRVJUIElOVE8gZmVlZGJhY2sobmFtZSwgZW1haWwsIGNvbW1lbnQsIGRhdGV0aW1lLCBTSUQpIFZBTFVFUygnXCcnLCAnJycsICdcJ ycsICcxNS0wMy0yOCAwOTo0MjoxOScsICdic3NpaWx1NjBvOWJiNGFzZHB1MTM1ZmtnMScp.jpg height=0 width=0>
Though there are no equal signs at the end, the ALT value (without the .jpg extension) is the Base64 encoding of the following string, which represents the SQL query that was executed and failed:
INSERT INTO feedback(name, email, comment, datetime, SID) VALUES('\'', ''', '\'', '15‐03‐28 09:42:19','bssiilu60o9bb4asdpu135fkg1')
The problem is indicated in red: the handle parameter (corresponding to email in the table) is not escaped! Indeed, setting handle to be
' + (SELECT VERSION()) + '
works… but only partially.
The problem is that MySQL string concatenation requires an explicit function call, and addition (with a + sign) treats strings as numbers, thus returning only part of the version (5.6) in the handle entry in the guestbook. We are, however, lucky: the comment column (which contains the feedback) appears after the email column, so we can ignore the rest of the existing query by commenting it out, and thus rewrite it entirely with
', (SELECT VERSION()), '15‐03‐28 09:42:19', 'bssiilu60o9bb4asdpu135fkg1')#
The full query becomes as follows, with the original part of the query in blue, the inserted value in red, and the commented out part in strikethrough grey:
INSERT INTO feedback(name, email, comment, datetime, SID) VALUES('', '', (SELECT VERSION()), '15‐03‐28
09:42:19', 'bssiilu60o9bb4asdpu135fkg1')#', '', '15‐03‐28 09:53:25', 'bssiilu60o9bb4asdpu135fkg1')
Note here that doing the usual double dash (‐‐) for comments does not work, and that the session id (SID) needs to be the same as before (and the same as PHPSESSID), so that the injection can be viewed in the guestbook:
Success! Running similar queries with DATABASE(), USER(), @@DATADIR, and @@HOSTNAME gives us the values ctf, ctf@localhost, /var/lib/mysql, and ctf respectively, which are not all strictly needed, but good to know just in case.
Recovering Table and Column Names
The next step is getting the table names:
tableX', (SELECT table_name FROM information_schema.tables WHERE table_schema='ctf' LIMIT 1 OFFSET X), '15‐
03‐28 09:42:19', 'bssiilu60o9bb4asdpu135fkg1')#
Altering the value of X (starting at 0) gives us the following tables: accounts, feedback, and items. Similarly for the column names:
YcolumnX', (SELECT column_name FROM information_schema.columns WHERE table_schema='ctf' AND table_name='Y'
LIMIT 1 OFFSET X), '15‐03‐28 09:42:19', 'bssiilu60o9bb4asdpu135fkg1')#
The accounts columns are id, account_id, account_pin, lastname, firstname, and balance, while for items they are id, name, price, brief, and private.
A reasonable assumption to make is that the flag is in the items table for an entry that has the private column set:
private', (SELECT private FROM items WHERE private IS NOT NULL), '15‐03‐28 09:42:19', 'bssiilu60o9bb4asdpu135fkg1')#
As seen above, the value we get is:
which can be Base64 decoded to:
which after a ROT13 becomes:
http%3A%2F%2Fdc22.secur3.us%2Fchal2%2Fregister.html to be URL decoded as:
This was the first flag as confirmed by a DM and a public shoutout!
Red Herrings and Easter Eggs
Of course, not everything was this linear and on the right track. For one, there were some weird comments in the guestbook source. As an example, the word “test” was represented as t<!‐‐e‐‐>e<!‐‐t‐‐>s<!‐‐set‐‐>t. This was possibly to make XSS and automated injections harder, but it turned out to be irrelevant at the end.
An injection was also possible using the PHPSESSID variable. An empty value or a value with quotes revealed the format of yet another table:
INSERT INTO guestbook(message,handle,contact,SID) VALUES('1','2','3','');
Once more, this table did not matter, and from the investigation above it looks like it doesn’t even exist! This was quite problematic when I was initially testing the injection, because I couldn’t use either the guestbook or the feedback tables.
Finally, for completeness, the other columns for the flag were Flag, $59.10, and This is not the flag you are looking for. (Or is it?). The other rows contained a lot of references to the TV series Lost.
Now level 1 is complete, you’ll have to wait until part two to find out how I finished the challenge.
About the Author: Ilias Giechaskiel is currently a PhD student in Cyber Security at the University of Oxford. He holds a Master’s in Advanced Computer Science (Distinction) from the University of Cambridge, and a Bachelor’s in Mathematics (Summa Cum Laude) from Princeton University. Ilias has interned in the Windows Security team at Microsoft and the Product Abuse Security team at Dropbox after a financial internship at Bloomberg. His website can be found at https://ilias.giechaskiel.com/.
Editor’s Note: The opinions expressed in this guest author article are solely those of the contributor, and do not necessarily reflect those of Tripwire, Inc.