tl;dr
/source
to get the source- Access local host from
dev_test
using SSRF - SQLI to get the flag path a nd LFI to get the flag
Challenge Points : 700
No. of solves : 27
Challenge Author : Rohit, Skad00.sh, Malf0y, Careless_finch
Description
Our new recruit worked on our new super secure file store and i am pretty sure he is good at what he does,it looks awesome.
Introduction
This is our first challenge that we made for a CTF. The main idea is to chain 3 common vulnerabilities (SQLI, SSRF, LFI). We have made sure there is no guessing involved in our challenge. There was also an unintended solution. Hope everyone enjoyed the challenge.
Intended solution
First we have to get the source of the web application from the /source
endpoint (you can also get it using LFI). Going through the source you can find the /dev_test
endpoint which is sending a get request to the URL we provide it. The URL is validated using the url_validate() function.
1 | def url_validate(url): |
This is vulnerable to SSRF as it is URL decoding the input before sending the request. So we can bypass the filters by URL encoding our input (or you can brute-force the container ip :stuck_out_tongue_winking_eye:). Going through the source you can also find that the /return_file
is vulnerable to LFI because the filename is concatenated without any sanitization.
1 |
|
Visiting the local host using the SSRF we discussed above you can find the php page which is clearly vulnerable to SQL Injection.
1 | <?php |
The script is executing the first query $query2
. It is only executing the second query if there is an error in executing the first query. The intended solution is to error out the first query and to use blind injection in the second query to get the path.
To make an error in the first query we have to give just a '
but that is blacklisted. URL encode comes again to save us. In the code you can see that we are again URL decoding the input. So we can put %252527
to error out the first query.
In the second query there is a strict filter and there is a length restriction of 124 characters. The final payload is : 1,name from adminfo where path like 0x2f{x}25 union select 1
Note : This is a payload of exact length 124, anything with more length than this will not give you the full path. You can check the path you got is correct or not by just removing the 25
or you can check with where path={path_you_got}
and confirm.
After getting the flag file path from the database. We can use the LFI mentioned above to download the flag file.
This is our final exploit.
1 | import requests |
Unintended
The unintended solution is that we are blindly returning any file that you ask for. So you can pretty much download anything from the file system. As the requests are logged in the apache logs(access.log), you can find others solve script in there.
You can also download /var/lib/mysql/challenge/adminfo.ibd
which will have the flag path.
It was a great learning experience for us. Congratulations for all those who solved it and all others who tried their best.
Flag :
inctf{y0u_pr0v3d_th4t_1t_i5_n0t_53cur3_7765626861636b6572}