Link: https://ctf.redpwn.net/
pastebin-1
Category: Web
Author: BrownieInMotion
Description
Ah, the classic pastebin. Can you get the admin’s cookies?
Solution
For this challenge, we are given two links. One is a mock pastebin website where you can enter text, submit it, and be given a link to where it persists. The second link is a website that allows you to redirect a bot to a specific URL.
Based on the nature of the websites, and the description of the challenge, it’s fairly clear that this is a classic XXS challenge. The mock pastebin website allows JavaScript that we write to be injected into the DOM of whoever visits the page. We can exploit this to steal a cookie of whoever visits the page with our JavaScript injection.
First, I created a public RequestBin as an endpoint for our exploit. Then I created a new paste with the following content:
I then took the link to the newly created paste and fed it to the admin bot. The flag then appeared as a GET parameter in the RequestBin.
When the admin bot visits our link the JavaScript within the <script>
tag gets run. The script tries to create an image with the source of our RequestBin and the admin’s cookie as GET parameter. The admin bot will then make a request to our endpoint which we can capture, thus exposing the cookie which contains the flag.
Flag
flag{d1dn7_n33d_70_b3_1n_ru57}
secure
Category: Web
Author: BrownieInMotion
Description
Just learned about encryption—now, my website is unhackable!
Solution
For this challenge, we are given a web page with a simple login screen. Attempting to log in with some random credentials will show the SQL query that was run by the backend.
We are also given the application code in index.js
. Reading through this code we can see that it is SQL injectable:
Attempting to SQL inject doesn’t seem to work. Trying to use the username ' OR 1=1; --
produces the following output:
The username injection here seems to be encoded in base64 which is preventing the injection from completing. The source code of the login page supports this, showing that the username and password inputs are base64 encoded on the client-side before being sent to the server using the btoa()
function.
We can pass our injection to the server using a tool like curl to ensure our username/password does not get encoded. I found that it was easier to inject on the password instead of the username. Using the following command will print the flag url encoded:
We can then use a tool like CyberChef to easily decode the flag.
Flag
flag{50m37h1n6_50m37h1n6_cl13n7_n07_600d}
cool
Category: Web
Author: Arinerron & BrownieInMotion
Description
Aaron has a message for the cool kids. For support, DM BrownieInMotion.
Solution
For this challenge, we are given another simple login screen. It also looks like we can register an account. If we register an account and log in, the following message is shown:
This indicates that there is a user called ginkoid that we need to log in as. Trying to register a new user with this account will tell us that the username is taken, indicating that the user does exist in the database.
In addition to the website, we are also given the source code in app.py
. By the looks of it, this is a Flask application running SQLite3 as the database. When the app is started the init()
function is called which generates the database tables and adds the ginkoid user.
The password for ginkoid is generated using the generate_token()
function, which creates a random string of 32 alphanumeric characters.
Looking further at the code, we can see that most of the SQL queries are vulnerable to SQL injection. This is because they are build using f-strings, which is just a fancy string formatting mechanism. However, attempting to SQL inject on the login query will not work, as usernames with any non-alphanumeric characters (as defined by the allowed_characters
set) will be denied.
This same check for non-alphanumeric characters happens in the create_user()
function as well, however, it only checks the username input and not the password input. This means that we can SQL inject only when setting the password when registering a new user.
The injectable query is an INSERT
statement. One thing to note is that the password must be less than 50 characters long, thus limiting the length of our SQL injection. The process to extract ginkoid’s password is the following:
- Create a new user with any username and a password that is one character of ginkoid’s password at some index i, starting with i=0.
- This can be done by injecting a sub-query that selects ginkoid’s password from the
user
table and taking a substring at index i of length 1. - The following injection works to create the password
'||(SELECT substr(password,1,1) FROM users))--
.
- This can be done by injecting a sub-query that selects ginkoid’s password from the
- Do a blind SQL injection on the newly created user. Iterate through each alphanumeric character and try to log in. When you log in successfully, you know the character that is at index i of ginkoid’s password.
- Repeat this process 32 times, incrementing i by 1 each time. Gradually extract ginkoid’s password one character at a time.
I wrote the following script to automate this process:
Running this script gets the password eSecFnVoKUDCfGAxfHuQxuootJ6yjKX3
. When we log in to ginkoid using that password we are given an audio file with the name flag-at-the-end-of-file.mp3
. Running cat on the file gives us the flag.
Flag
flag{44r0n_s4ys_s08r137y_1s_c00l}