Category | Challenge Name |
---|---|
Web | My first Website |
Web | Glacier Exchange |
Web | Peak |
The website has the functionality to input two numbers and perform a calculation.
Continue by clicking 'here' to view the details of other project on the website.
I realize that when accessing /projects, the name of it is also displayed.
Ohhh, it seems like that might be Server-Side Template Injection (SSTI).
I perform a test injection with {{7*7}}
The result I received is 49. So, the next step is to test what server is currently being executed.
Reference link: https://book.hacktricks.xyz/pentesting-web/ssti-server-side-template-injection
https://hackmd.io/@onsra03/By77nbQv2 (SSTI)
If you want to understand how the payload works, please refer to the write-up link I provided.
OK, continuing with fuzzing, I discovered that the website uses Jinja2 templates.
Now I will execute commands and search for the flag file.
With payload: {{cycler.__init__.__globals__.os.popen('command inject').read()}}
Solution: {{cycler.__init__.__globals__.os.popen('cat /flag.txt').read()}}
Download src: Here
The website has a currency conversion feature allowing you to convert values from one currency to another.
I have 1000 Coins cashout, and I will try to transfer 1 coin to Doge.
Request header:
OK, next, let's take a look at the provided source code.
In the server.py
file, you will find the APIs responsible for implementing the money transfer functionality.
Note that here:
inClub = wallet.inGlacierClub()
float(payload["balance"])
In file src/wallet.py
:
So initially, we have cashout = 1000
And inClub
is true when:
In this challenge, I have two ideas:
But it failed
2. Transfer a negative amount or potentially use INF
and NaN
values.
So, how are we going to do it? As I mentioned, we will focus on exploiting float type casting during money transfers
The first step is to perform a transfer with a negative amount.
And check /api/wallet/balances:
So, we achieve the first condition: cashout > 1000000000
Becase:
The code only checks if the transferred amount is greater than the current balance. If it is, it subtracts that amount from the current balance.
So: 1000 - (-99999999999999999) = 1.00000000000001e+17
Subtracting a negative amount is equivalent to adding that amount 🤣
It's logic bug…
Next, to make the doge Coin return to 0, what do we need to do?
1e230 = 1×10^230
It means that when we perform a subtraction with a very large negative number, it will effectively add that number to the current balance. It will then cast the result to the maximum representable number.
Execute the following steps:
http request:
And we get the result:
Finally, we just need to transfer 1e+230
from Doge
to Ascoin
Got flag:
gctf{PyTh0N_CaN_hAv3_Fl0At_0v3rFl0ws_2}
Solution 2 from Kaiziron:
Download src: Here
This challenge might have an unintended solution, but I'll solve it using the intended method first.
In the docker-compose building file docker-compose.yml, we can see how the docker containers were built:
And:
There are two things to note here:
Overview of the source code is as follows:
admin.py
file in the admin-simulation folder handles the login with the 'admin' account and access when we send a contact.And file .htaccess:
In file /includes/config.php:
We see password admin, but it hashed, and cant crack it:
Let's analyze the files inside the /actions folder together:
In the three files: login.php, logout.php, and register.php, functionalities are implemented as indicated by their names, and there don't seem to be any vulnerabilities here.
File contact.php:
Main Code:
This part checks if the request method is POST, if the user is logged in, and if the user is not an admin. If these conditions are met, it processes the form data.
Includes Session Handling:
Includes a file ("session.php") for managing sessions and user authentication.
Function to Cleanup Old Files:
Defines a function (cleanup_old_files()) to remove files in a directory older than 5 minutes.
Main Form Submission Handling:
Checks if the request is a POST request from a non-admin user.
Checks if the uploaded file is a valid image (based on extension and content), moves the uploaded file to a specified directory, and sets the $target_file variable with the path to the uploaded file.
The form data (title, content, user_id, and file) is retrieved from the POST request, and an SQL INSERT query is prepared and executed to insert the data into a database table named "messages."
Success and Exception Handling:
If the database insertion is successful, a success message is stored in the session.
If an exception occurs during the execution of the try block, it catches the exception, stores the error message in the session (after HTML encoding it), and continues with the redirect.
Redirects:
Finally, the user is redirected to the "/pages/contact.php" page, regardless of whether the form submission was successful or encountered an error. The appropriate message (success or error) will be displayed on the redirected page based on the session variables set earlier.
Let's focus on the code in the next two files:
In file /pages/view_message.php
And file /includes/csp.php:
So, we can see an XSS vulnerability with the content, and this challenge has the additional challenge of Content Security Policy (CSP)
Assuming we have the admin's session, what would be the next step?
In file /admin/map.php:
We see: libxml_disable_entity_loader(false)
Ohhhh, it seems like the next step might involve XML External Entity (XXE) injection.
Follow the exploit as follows:
How do we plan to bypass CSP?
In simple terms, this Content Security Policy is instructing the browser to only allow the execution of scripts that originate from the same domain as the web page. Any attempt to execute scripts from external domains or inline scripts would be blocked.
Reference the following link before proceeding with the exploitation:
Exploiting the image upload function in the contact feature, we will insert XSS code into it. In the content section, we will call the image file to execute XSS.
I'm using the tool to create an image containing the XSS script
Use command:
Then, we will upload the image we just created and retrieve the image link
Next, we will upload the second image with the following content:
<script charset="ISO-8859-1" src="/uploads/link-your-img"></script>
We will obtain the admin's session.
And change session to login admin:
Finally, as analyzed before, we will go to edit map, performed in the map.php file
Payload:
Flag: gctf{Th3_m0unt4!n_t0p_h4s_th3_b3st_v!3w}
And I will now mention the unintended part of this challenge:
When we directly access /admin/map.php in the browser without an admin role, we will be logged out. However, when we do it through Burp Suite, we will not follow its redirection.
So, by directly accessing /admin/map.php with a session that doesn't have an admin role, we can still edit it directly and retrieve the flag.
Demo:
Role admin:
I will change session:
Thank you to the author and the organizers for creating such a fantastic CTF.