404 Bank
Challenge Lab (Medium) - by 2ubZ3r0
The following post by 0xb0b is licensed under CC BY 4.0
Scenario
Objective / Scope
404 Bank, a staple of the local financial community, is conducting its annual security assessment. To uphold their motto of being "Proven, Local, Strong," the bank has commissioned the Hack Smarter Red Team to perform an internal penetration test.
Initial Access
You have been provided with VPN access to their internal environment, but no other information.
Summary
Summary
In Bank 404 we begin only with VPN access and no other information.
Enumeration of the website reveals a downloadable executable, CorpBankDialer.exe, containing a Base64-encoded MD5 hash that, once cracked, provides a valid password. Combining this with usernames generated from staff names found on the site, we authenticate as karl.hackermann. Using these credentials, we perform BloodHound enumeration and discover that karl.hackermann has GenericWrite permissions over tom.reboot. We escalate via Targeted Kerberoasting, extracting a TGS, and cracking it to recover tom.reboot’s password. From there, chained permissions allow ForceChangePassword over robert.graef, who in turn can ForceChangePassword over jan.tresor and other users. After adding jan.tresor to the Remote Desktop Users group and changing the users password, we gain RDP access and recover credentials for daniel.hoffmann from a deleted email.
As daniel.hoffmann, we pivot to the webadmin user by resetting its password, then access an internal port 5000 service via Ligolo tunneling. Downloading and cracking a password-protected configuration archive yields credentials for svc.services, initially disabled. Using robert.graef’s WriteAccountRestrictions privilege, we re-enable the account and authenticate successfully. With svc.services belonging to the Certificate Service DCOM Access group, we identify a vulnerable Vuln-ESC4 template and exploit it using Certipy by reconfiguring it to an ESC1-style template and requesting a certificate for Administrator. Authenticating with the generated certificate provides the NT hash of Administrator, enabling domain compromise and retrieval of the final flag from the Administrator’s desktop.
Recon
We use rustscan -b 500 -a 10.0.28.235 -- -sC -sV -Pn to enumerate all TCP ports on the target machine, piping the discovered results into Nmap which runs default NSE scripts -sC, service and version detection -sV, and treats the host as online without ICMP echo -Pn.
A batch size of 500 trades speed for stability, the default 1500 balances both, while much larger sizes increase throughput but risk missed responses and instability.

The target machine is actually a domain controller with exposed services including DNS 53, Kerberos 88/464, an IIS /10.0 web server on port 80, multiple MSRPC endpoints 135, 593, 49664+, SMB 139/445, LDAP and LDAPS 389/636/3268/3269 tied to Active Directory, RDP 3389, WinRM on 5985, and .NET Remoting 9389. This indicates a fully integrated Windows AD environment where LDAP/LDAPS and Kerberos provide authentication, SMB and RPC enable remote management, and RDP/WinRM serve as remote access points.

WEB
We start our enumeration on the web server on port 80. We first visit the page with our browser and find a static site infront of us.

As we scroll through the page, we also find a team of three people.

We note down the individual names of the team members so that we can generate usernames from them later for later use.
On the Services page, we also find an executable file. We download this file.

Enumerating the directories using Feroxbuster did not yield any useful results.

SMB
Before we dive in with username enumeration we try to authenticate as guest and anonymously against SMB, but without success. Nevertheless we generate the hosts file entry like the following

We add the following to our /etc/hosts file. We could also directly append the entry to our hosts file by providing the path to /etc/hosts in the NetExec command.
Access as karl.hackermann
During preliminary analysis using strings of the downloaded CorpBankDialer.exe, we find a DEBUG string encoded in base64.

When we decode this, we get an MD5 hash. We then try to crack this. It could be a secret, or password me might need to use later.

We crack the MD5 hash using hashcat and, based on the result we get, we are clearly dealing with a password.

We have a password and a set of names from the team. What we still need are usernames to test the password against SMB or other available networks.
We generate these using username anarchy.

Next, we try every possible username from our username-anachry result with the password found from the executable. And in the end, we are successful; we can successfully authenticate with the password as karl.hackermann.

We don't see any special shares at first.

BloodHound enumeration
With the credentials, we can now also enumerate the AD using BloodHound.

We are able to identify Administrator as one of the Domain Admins.

As karl.hackerman, we have GenericWrite permission over tom.reboot. With this, we can either perform a targeted Kerberoast attack to obtain a crackable service ticket, or carry out a shadow credentials attack, which would allow us to authenticate as tom.reboot without knowing their password like we did in Arasaka:

When we look at the shortest path from our owned object, we see that we can start from karl.hackermann, who has GenericWrite permissions over tom.reboot. This allows us to perform either a targeted Kerberoasting attack or a shadow credentials attack like mentioned before. Using this access, we can ForceChangePassword on tom.reboot, which in turn gives us control over robert.graef. From there, we can all compromised users to the Remote Management Users group.
Furthermore, as robert.graef, we can ForceChangePassword on nina.inkasso, melanie.kunz, and jan.tresor.

If a more recent version of bloodhound-ce.py is used, it might be possible to see even more permissions that robert.graef has. These will be necessary for the subsequent privilege escalation. Even though we cannot see them here in the output, we can still use them. More on this when we get to that point. For now, we can continue as follows.
Access as tom.reboot
From our Bloodhound analysis we know that karl.hackermann has a GenericWrite relationship to tom.reboot. This allows either a TargetedKerberoast or Shadow Credentials Atttack.
With the GenericWrite permission we are able to modify tom.reboot's servicePrincipalName (SPN), we request a service ticket for it, and perform offline Kerberos ticket cracking to recover its password.
In a Shadow Credentials Attack we abuse the GenericWrite permission to add a malicious key credential to tom.reboot, allowing authentication as that account without knowing its password.
We will show both options.
TargetedKerberoast
We'll start with the TargetedKerberoast. See below links for further reading:
This abuse can be carried out when controlling an object that has a
GenericAll,GenericWrite,WritePropertyorValidated-SPNover the target. A member of the Account Operator group usually has those permissions.The attacker can add an SPN (
ServicePrincipalName) to that account. Once the account has an SPN, it becomes vulnerable to Kerberoasting. This technique is called Targeted Kerberoasting.
To perform the TargetedKerberoast we will use the following tool:
We run the following command and are able to get the Kerberos 5, etype 23, TGS-REP blob of the tom.reboot user.

We use hashcat to crack the blob and are able to retrieve the password of tom.reboot.

We test the credentials using NetExec. We successfully authenticated. We could now move on, or try the Shadow Credentials Attack.

Shadow Credentials Attack
The following Section descirbes the Shadow Credentials Attack it's an alternative path to the TargetedKerberoast attack and can be skipped.
Further information on the Shadow Credentials Attack can be found under the following link:
To perform the Shadow Credentials Attack we are using Certipy.
In short: If we can write to the msDS-KeyCredentialLink property of a user, we can retrieve the NT hash of that user.
With the following command we issue the attack and are succesful. We retrieve the NT hash of tom.reboot.

We test the credentials using NetExec. We successfully authenticated. We could now move on.

Access as robert.graef
From our Bloodhound analysis we know that tom.reboot has a GenericWrite relationship to robert.graef. This allows us to change the password of the user. The following resource showcases the different tools we could use to change the password of the user.
We will be using bloodyAD.
Next, with the following command we change the password for robert.graef to Pwned123@!.

We test the credentials using NetExec. We successfully authenticated. We move on.

RDP session with jan.tresor
From robert.graef, we can ForceChangePassword on nina.inkasso, melanie.kunz, and jan.tresor. For now we will focus only on jan.tresor as thats the user having some valubale loot for us later.
With the following command we change the password for jan.tresor to Pwned123@!.

We test the credentials using NetExec. We successfully authenticated. We move on.

However, the user jan.tresor is not in the Remote Desktop Users group. That doesn't matter, because as robert.graef we can add users to this group thanks to the AddMember permission. We did this for all users in order to check for each initial access whether there was anything to be gained. However, we only found something with jan.tresor. To add a member to the group Remote Desktop Users we use also bloodyAD.

After we have added jan.tresor to the Remote Management Users we are able to RDP into the machine. On the Desktop we find a full recycle bin.

Shell as daniel.hoffmann
In the recycle bin, we find some email copies (.eml files). One of them may contain something valuable.

The Mail Access Credentials - Don't tell Anyone stands out in particular. Maybe we'll get lucky. In it, we find the password for Daniel Hoffmann.

We test the credentials using NetExec. We successfully authenticated. We move on.

The user daniel.hoffmann is in the remote management user group, which would allow us to use evil-winrm for a session. We are testing this.

We connect to the target machine as daniel.hoffmann using evil-winrm and find the user flag at C:\Users\daniel.hoffmann\Desktop\user.txt.

Access as webadmin
We check our BloodHound data again to see if we can do more with daniel.hoffmann and see that he also has ForceChangePassword permissions. This is for the user webadmin.

However, it seems that we cannot proceed any further from webadmin. This could be a dead end or a clue. We have not enumerated further on the server yet. It is possible that an internal web server is running on it, from which we could proceed further.

We look at which ports are being listened to and find port 5000.

We try to request it in the session using the curl alias, but we have to authenticate ourselves. We make the internal ports available to our attacker machine using Ligolo, but we could also do this on a smaller scale with Chisel.

Ligolo-ng setup
We will be using the latest release v0.8.2:
First, we run a proxy.

Inside that proxy we create an interface called bank.
Next, we add a single route to the interface to reach the internal services of the host.


After the connection has been made we should see in our proxy that an agent has joined.

We can list and interact with the session by calling session and then chosing the session. The following screenshot illustrates the steps taken.
After chosing the session, we can start the tunnel.
To confirum our tunnel and routes we can issue the following commands:

We can now reach the internal web service running on port 5000 via http://240.0.0.1:5000. This requires basic authentication.

We'll try using the webadmin. But first we need a password for it. We'll change the password as usual using bloodyAD.

Access as svc.services
Next, we enter our set credentials...

... and are able to login. We can download service config_backup.zip file.

The zip file is password protected. Using zip2john, we generate a hash that we then attempt to crack.

However, our rockyou.txt does not seem to contain the password.

We are trying to generate a word listfrom the keywords on the website. We extract these using cewl.

Using our generated word list, we were able to successfully crack the password of the zip file and unzip its contents.

The zip file contains a config.dat file that contains the credentials for the user account svc.services.

We test the credentials using NetExec but the account is disabled.

Here is the crucial part that I missed in my initial enumeration. My version of bloodhound-ce.py does not seem to capture all relationships between the object completely.
In addition to ForceChangePassword, robert.graef has other permissions, including WriteAccountRestrictions on svc.service. This allows us to re-enable the svc.services account.
What WriteAccountRestrictions allows:
It lets you modify attributes that control logon behavior, including:
userAccountControlLogon hours
Workstation restrictions
And ACCOUNTDISABLE is just a bit inside userAccountControl
I received this tip from Schlop, who also introduced me to the GriffonAD tool, which is similar to a text-based version of Bloodhound. I think it's a very cool tool that provides a good overview in small environments.
He also showed me his version, which he forked to implement additional features such as reading the entire zip file from a BloodhHound enumeration.
We enable the account like the following using bloodyAD.

We test the credentials using NetExec again and this time we can successfully authenticate.

Shell as Administrator
The svc.services account is member of the Certificates Service DCOM Access group.

We check if we can find any misconfigured certificate templates to escalate our privileges. We find one. The template Vuln-ESC4 is vulnerable to ESC4. ESC4 means we have write permissions on that certificate template, so we can modify it (for example, add dangerous EKUs or enable user-supplied SANs) and turn it into an ESC1-style vulnerable template

Template name:

We can follow the guide of certipys wiki if we are using the current version 5.0.2:
Step 1: Modify the template to a vulnerable state. Certipy's
templatecommand with the-write-default-configurationoption is a convenient way to automatically reconfigure a target template to a known ESC1-like vulnerable state. This option typically:
Enables "Enrollee Supplies Subject" (
msPKI-Certificate-Name-Flag = ENROLLEE_SUPPLIES_SUBJECT).Adds the "Client Authentication" EKU (
pKIExtendedKeyUsageandmsPKI-Certificate-Application-Policy).Grants "Full Control" (which includes enrollment rights) on the template to the "Authenticated Users" group (by modifying
nTSecurityDescriptor).Disables manager approval (
msPKI-Enrollment-Flagadjusted,PendAllRequestsremoved).Sets "Authorized Signatures Required" to 0 (
msPKI-RA-Signature = 0).Clears any existing RA Application Policies (
msPKI-RA-Application-Policies). This command also automatically saves the template's original configuration to a JSON file before applying changes.
But in my case I m using the old version of certipy.

For a reference I suggest the following resource on how to exploit ESC4 with certipy 4.8.2:
We modify the certificate template...

... and afterwards request a certificate that impersonates the Administrator account to obtain an authentication certificate for administrator@404finance.local.
Step 2: Request a certificate using the modified template. The attacker now requests a certificate for a privileged user (e.g., Administrator), leveraging the ESC1 vulnerability they just created in the "SecureFiles" template.

Next we authenticate using the the obtained certificate. We are able to retrieve the NT hash of the administrator accoiunt.
Step 3: Authenticate using the obtained certificate.

We use the hash to authenticate as Administrator via Evil-WinRM, and retrieve the final flag at C:\Users\Administrator\Desktop\root.txt.

Last updated
Was this helpful?