PicoCTF 2018 writeup: A Simple Question
Here’s a walkthrough of my approximate solution path for the problem “A Simple Question” in PicoCTF 2018. This was a fun problem about nontrivial but not particularly advanced SQL injection. There are probably many other good resources on better techniques than those presented here - I am not an avid CTF player, only dabbling in it a little from time to time - but I hope this can serve as a guide for taking the first steps beyond the bare basics of SQL injection.
Chapter 1: Exploration
“A Simple Question” was a problem for 650 points in the Web Exploitation category, and its prompt was:
There is a website running at
http://2018shell2.picoctf.com:2644
(link). Try to see if you can answer its question.
Visiting this URL, I’m greeted by this simple form:
All right. First thing to do on web exploitation problems is to view the page source…
Nothing immediately springs out as important here… except the comment source
code is in answer2.phps
. So let’s see what I find at
http://2018shell2.picoctf.com:2644/answer2.phps
.
Ok, so there’s some kind of mangled display of some kind of source here. This
doesn’t look like all of it, but there are plenty of hints on what I need to
achieve. Before I dig deeper into this, I’ll try poking a little at that form.
There’s something about SQL in the “source”, so I’ll try right away with a
minimal SQL injection attempt by posting ';--
.
Oh, so I actually get to see the query! That’s helpful — if it’s true,
that is. Assuming it is, I see I can trivially make the WHERE
clause evaluate
to true with the input ' OR 1=1'; --
:
Ok, something happened!
Chapter 2: Ideation
Let’s go back and take another look at Figure 3. It looks like my
goal is to execute that code containing $FLAG
… and it looks like that code
path is preceded by a comparison between $answer
and $CANARY
. I’m not sure
what $answer
is, but $CANARY
hints at some kind of guard value. Maybe there
are multiple rows in the database, including a sentinel value $CANARY
,
arranged in such a way that all but a specifically crafted query will select
that sentinel value and let the code detect the SQL injection? What if I sort
the result set?
Hm, no apparent difference. Can I crash the SQL query?
Woop, indeed I can. At this point I tap into my rather limited CTF experience and remember something about conditional crashes as a way to work with almost-blind SQL injections, so I spend some time trying to make the query crash depending on the outcome of the query. I try to build something from short-circuit logic…
' OR 1=1 AND (answer < "a" OR (1/0 = 1)); --
…but nothing I try seems to work — the zero division doesn’t crash the query, and references to undefined names crash the query unconditionally. My SQL-fu is clearly lacking here.
But hey, maybe I don’t need any of that to make use of the idea answer < "a"
?
Bingo! Looks like I’m onto something here.
Chapter 3: Assessment
So I’m starting to build up a concept for a solution. Let’s see what else I can
probe for. Can I find the length of the answer
?
All right, so now I know that the answer is 14 characters long, and that I can
probably binary search for the first character. So, remembering that the
ASCIIbetical order of alphanumeric characters is 0-9A-Za-z
, I go ahead and try
that:
A-ha! Found you! Looks like the first character in the answer
is 4
.
Chapter 4: Execution
I now have a fully baked solution method in mind, so it’s just a matter of repeating the above process for the remaining 13 characters. If I was a more routined CTF player I would probably automate this, but since I know the length I decide that it’s probably more efficient to just go through it manually.
A-ha! There it is! …but it seems like I’m not fully done yet…
Oh right, remember the $CANARY
from Figure 3? if ($answer ==
$CANARY) { echo "Perfect!";
? What if…
Wohoo, there we go! 650 points to me!
Epilogue
So there’s as accurate a recount as I can manage of my journey through this problem. It was a fun and rewarding challenge, but ultimately not terribly advanced. I hope this can help someone learn a thing or two about what one can do with SQL injections beyond — but without needing much more than — the bare basics. Thanks for reading!