Details
Platform: HackTheBox
Difficulty: Medium
Link: Under Construction
Enumeration
Start the challenge instance and download the resource package:
Navigate the browser to http://ip:port/ and enter test as the “Username” and “Password” and click “Register”:
(Note: My instance was deployed at http://206.189.25.23:30830)
Start Burp Suite
and configure the browser’s HTTP proxy:
(Note: My Burp proxy is the default: http://127.0.0.1:8080)
With Burp running and intercepting HTTP traffic via the proxy, login to the web app with the registered test account.
“Forward” the initial login request via Burp:
Again, using Burp, send the web app’s redirect request, including the Cookie: session=
token to Burp’s “Repeater”:
(Note:: Press Ctrl-R to send the request to Burp’s repeater.)
JSON Web Token (JWT)
Perusing the provided expressjs
web app’s source code, the above session cookie, or, “token”, is generated and sent as an HTTP redirect response in the route file “routes/index.js”:
The JWTHelper.sign(...)
can be traced to the file “helpers/JWTHelper.js” which subsequently includes a requires
for jsonwebtoken
:
Googling “jsonwebtoken vulnerabilities”, this library is vulnerable to “Authentication Bypass”, as described here.
This vulnerability, known as CVE-2015-9235, describes “JWT HS/RSA key confusion vulnerability” whereby a vulnerable server-side (jsonwebtoken in this case) successfully verifies a token by erroneously:
- Expecting “RSA” (public-private key scheme), but instead receiving “HSA256”(symmetric-key scheme); an attacker can easily forge a token with an updated “alg”
- Blindly passing the re-purposed public-key as the verification key to the server-side verification method, confusing the known public-key as the verification key for HS256
Copy the JWT token from the session cookie from the request in Burp’s Repeater, and use jwt.io to decode it. Note the “alg” type “RS256” and that the payload data includes a public key element “pk”:
As shown above, the decoded JWT token’s header designates “RS256” as the algorithm and the payload divulges the server-side public-key - the two requirements for CVE-2015-9235.
Download jwt_forge.py locally and copy the encoded JWT token from Burp’s repeater to a file for easier management, e.g. “jwt_token_example.txt”. Execute jwt_forge.py
passing in the copied JWT token and registered username “test”:
(Note: I wrote jwt_forge.py
to learn about JWT tokens and solve the “Under Construction” challenge.)
Copy the “forged” token from the terminal output and paste it over the current token in the request in Burp’s Repeater window; send the request to the web app by pressing “Send” and confirm the user is still authenticated as “test”:
SQL Injection (SQLi)
Spending more time reading the source code, there looks to be a simple SQL injection in “helpers/DBHelper.js” which interfaces to an SQLite3
database; the user-supplied input variable ${username}
is concatenated with the SQL “SELECT” statement in the DBHelper.getUser(...)
helper:
DBHelper.getUser(...)
, is called via the result of an async call from “middleware/AuthMiddleware.js”’s AuthMiddleware
as highlighted in “routes/index.js”:
The provided parameter req.data.username
, susequently passed to the SQLi vulnerability in DBHelper.getUser(...)
is the username from the JWT token, extracted as of middleware AuthMiddleware
:
Re-forge the last “forged” JWT token using jwt_forge.py
; pass a “UNION” injection to test the SQLi vulnerability:
Again, copy the “forged” JWT token to the same Burp Repeater window and “Send” the request:
(Note: Having the “2” replace “test” as the username - this SQLi is not “blind”.)
With the jwt_forge.py
+ Burp Repeater process, inject the follow commands:
SQLite Version
$ python3 jwt_forge.py $(cat jwt_token_example.txt) \
"test' and 1=2 UNION SELECT 1,sqlite_version(),3 -- -
...
Database Table Names
$ python3 jwt_forge.py $(cat jwt_token_example.txt) \
"test' and 1=2 UNION SELECT 1,group_concat(tbl_name),3 from sqlite_master -- -"
...
Database Table SQL
$ python3 jwt_forge.py $(cat jwt_token_example.txt) \
"test' and 1=2 UNION SELECT 1,group_concat(sql),3 from sqlite_master -- -"
Flag
Perform UNION injection to get the challenge flag and submit!
$ python3 jwt_forge.py $(cat jwt_token_example.txt) \
"test' and 1=2 UNION SELECT 1,group_concat(top_secret_flaag),3 from flag_storage -- -"