BitStream
Range (Easy) - by Tyler Ramsbey
The following post by 0xb0b is licensed under CC BY 4.0
Scenario
Objective/Scope
BitStream is a cloud storage provider that hosts sensitive data for enterprise clients. They have segmented their internal Active Directory environment (bitstream.hsm) and requested a full penetration test of their environment.
You have been provided with VPN access to their Active Directory environment.
Summary
Summary
In BitStream, we begin with external enumeration and discover a web server on port 80 alongside SSH on port 22. Manual browsing reveals a login page and a quote submission form at /quote. Testing the submission form for blind XSS, we craft image-based payloads targeting individual fields and confirm execution via a callback on the requirementsfield. A follow-up payload captures a valid session cookie, granting access as joey@bitstream.hsm.
Inside the employee portal, we discover an IDOR vulnerability in the messaging endpoint at /portal/messages/<id>, allowing us to iterate through message IDs and read conversations belonging to other users. Enumerating through the messages, we recover credentials for sql_svc.
With these credentials we authenticate to the MSSQL server on 10.0.1.7 via mssqlclient.py and confirm xp_cmdshellexecution, establishing a reverse shell as nt service\mssql$sqlexpress. Noticing SeImpersonatePrivilege is enabled, we leverage DeadPotato to escalate to NT Authority\System and dump the local administrator hash via its built-in Mimikatz functionality. Connecting via evil-winrm, we run PrivescCheck and uncover plaintext credentials for bob stored in WinLogon, then dump lsass with blindsight to extract his NTLM hash.
With bob as a foothold domain user, we tunnel through the SQL server using ligolo-ng to reach the domain controller in the segmented subnet. BloodHound enumeration via bloodyAD identifies eddie as Kerberoastable. We extract and crack his hash offline with hashcat, then RDP into the workstation as eddie. Inspecting saved browser credentials in Edge, we recover credentials for luisa.
BloodHound reveals luisa holds GenericAll over james, allowing a forced password reset. With james we access the Scripts SMB share on the file server, where an AD backup script exposes credentials for svc_backup. This account holds GetChanges/GetChangesAll permissions on the domain, enabling a DCSync attack via secretsdump.py to retrieve the domain Administrator hash and achieve full domain compromise.
Changelog
The Windows Build of the machines had to be patched to prevent unintended kernel exploits. Unfortunately, that breaks pypykatz because it doesn't work with the latest Server 2025 build. The tool pypykatz was used to dump the hashes and retreive the cleartext password of bob. As a workaround, you can use the KvcForensic tool, which was featured in the Guided Lab: Attacking LSASS:
However, this only gives us bob's NT hash, which can be cracked.
The wirte-up has been updated.
Recon
We use rustscan -b 500 -a 10.0.0.5 --top -- -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.

This is the public facing target running a web server on port 80 and we also have SSH available.

We will first enumerate the site manually

We find a login page, but it doesn't appear to allow us to enumerate users with the error messages. We haven't tested the timing yet. However, we haven't yet identified any known username-email combinations from the initial enumeration.

We can submit a quote. It might be reviewed by another user. This could be a vector for blind XSS to steal a session cookie for example.

web.bitstream.hsm
Access as joey@bitstream.hsm
We want to test for blind XSS. To do this, we'll set up a web server and design our XSS payloads so that, if they are successfully executed, they connect to our web server.

To determine which field was critical when an XSS attack was possible, we distinguish between the field names in our payloads based on the directory we are targeting.

We get a connection back on the requirements field.

Next, we prepare a payload to capture the cookies...

... and we successfully retrieve a session cookie.

We add this to the storage of our browser and get a session as joey@bitstream.hsm.

In the employee portal, we can access support tickets, quotes, and a internal messaging portal.

We access the messages.

Our first message starts with ID 3.

Lets test if we can access other messages by changing the id. And we are able to read the messages between tommy and jon. We have an IDOR / BOLA infront of us. A BOLA (Broken Object Level Authorization) or IDOR (Insecure Direct Object Reference), is a vulnerability where an application fails to verify that the authenticated user has permission to access a specific object

We iterate through the messages and finally find the credentials of sql_svc.

sql.bitstream.hsm
Shell as nt service\mssql$sqlexpress
The network appears to be segmented between the WEB on EXT, SQL, and FILE SHARE services and the workstations on Subnet 2 according to the network diagram. However, this is not the case; at the very least, we can directly access the devices in Subnet 2.

With the found credentials we try to connect to the mssql server. We will be using impackets mssqlclient.py and the following cheatsheet.

We're testing whether we can run commands using the xp_cmdshell, and it works. We are mssql$sqlexpress.

We prepare a powershell reverse shell using revshells.com.

Next, we set up a listener using Penelope.
We execute the reverse shell payload...

... and receive a connection to our listener. We can see that we have SeImpersonatePrivilege enabled.

Shell as Administrator
The SeImpersonatePrivilege is a powerful Windows privilege that allows a user or process to impersonate another user's security context. There are several Potato exploits available that allows to escalate to NT Authority\System. While testing the GodPotato and EfsPotato was not working. But there are many more. Like DeadPotato.
We download the exploit to the target system...
... and execute it. It suggest serveral options, like running command, running mimikatz or sharphound. This tool is fullfledged.

To confirm the exploit is working we issue a whoami command using the exploit and we see we are NT Authority\System.

Next, we try to dump the SAM and SYSTEM secrets and are able to retrieve the local administrator hash.

We could also spawn a reverse shell. Since we are running Penelope we can deatach the current session using CTRL+D or F12 (depends on the target system it is connected) and select the session. We are NT Authority\System but we do not have an elevated shell.

Bob's credentials and hash
We connect to the the SQL server as Administrator using evil-winrm with the Administrators hash.

From there we run PrivescCheck.ps1, a tool similar to WINPeas or PowerUp.

We download the report...

... and we see the Credentials were set in WinLogon for the user bob.

But we also need the hash. To dump the lsass we are using a tool called blindsight. We compile it like shown in the repository.
Next we upload and run the tool.
The resulting lsass.dmp file is a large file, the download may take a while.

To extract the hashes from the dump we are using pypykatz... but we do not receive the password of bob with the latest Server 2025 build and the used version of pypykatz.

But we have a workaround ready using KvcForensic also highlighted in thefree Guided Lab: Attacking LSASS:
We download the latest version of KvcForensics from https://github.com/wesmar/KvcForensic/releases/tag/latest. Next we make the static version executable and run it.

We inspect the results and have data for the user bob. Unfortunately, in this case, we don't have the password in plain text as we did before, but we do have the NT hash, which we can crack.


DEPRECATED

... and we spot the hash for bob.

Ligolo-ng setup
Now that we have a domain user, let's try to enumerate the domain. However, the domain controller is located in subnet 3, which is actually segmented. So we need to tunnel our traffic, because the DC is accessible from the SQL Server.

We will be using the latest release v0.8.2 of ligolo-ng:
First, we run a proxy.
Inside that proxy we create an interface called bitstream.

Now, we add the DCs IP as routes in CIDR notation.

Next, we upload an agent and connect to our proxy.

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.

We should now be able to reach out to the DC01.

We test the credentails of bob using NetExec and successfully authenticate agains the domain controller.

We do not find any shares, but we issue the following command to generate an entry for our /etc/hosts file.

We add the following entry to our /etc/hosts file.
Now that we have access to the domain controller and have confirmed that bob's credentials also work for the domain controller, we're going to try to enumerate the domain. Unfortunately, most of the collectors fail. However, we've had success using bloodyAD.

Next we ingest the collected data to our BloodHound instance.
The user bob is just a domain user without any privileges.

But we check for keberoastable user and spot eddie.

We can perform a kerberoast using Netexec.

Next, we crack the hash.

wkst.bitstream.hsm
The workstation does not provide any services besides two open ports for remote desktop and remote management.

Shell as eddie
We test the credentials of eddie gathered via kerberaosting and are able to authenticate via RDP. Note, that the admin flag might be a false-positive in this case.

We connect to the target as eddie using remmina.

Access as luisa
We do not find any services or scheduled task runnig. But there is the edge browser. Let's check if that holds any saved credentials. There is one entry for gitlab.

We open the entry and find the credentials of luisa.

We test the credentials on the SHARE and succesffuly authenticate.

share.bitstream.hsm

Every credential gathered so far were tested on the SHARE server but without success. We were only able to identify a share called Scripts. This might hold some valuable / sensitive information burried in the scripts.

Also with luisa we are not able to read the share.

Access as james
We check back our BloodHound enumeration and see that luisa has GenericAll permissions over jamses. This allows to change the password of the user james.

We change the password of james to our liking.

Next, we connect to the share server again. This time we are able to read the Scripts share.

DC01.bitstream.hsm
Access as svc_backup
We connect to the share using impackets smbclient.py. Inside that share we find four scripts.

The Automated-AD-Backup script holds the credentials of svc_backup.

Next, we test the credentials using NetExec and are successful.

Unfortunately we cannot get an interactive session using impackets smbexec.py. We can access the C drive through smbclient, but do not have sufficient permssion to reach the flag in the Administrators Desktop.

Shell as Administrator
The svc_backup user has GetChanges/GetChangesAll permissions on the domain, allowing us to perform a DCSync attack and retrieve password hashes for any domain account.

We perform the DCSync via impackets secretsdump.py and are able to retrieve the Administrator hash from the DC.

We connect to the DC using evil-winrm as the administrator and find the final flag at C:\Users\Administrator\Desktop\root.txt.

Last updated