Windows Privilege Escalation 01: Initial Enumeration

Hands-on walkthrough of Windows PrivEsc fundamentals, with network recon, Defender analysis, AppLocker parsing, and process enumeration. Real command output and the reasoning behind every step.
Windows Privilege Escalation 01: Initial Enumeration

Hey, how's it going? Are you feeling well? Have you drunk enough water today? If not, see this as your calling before reading along!

Before this series dives into the depths of Windows PrivEsc, I thought I'd throw in some quick references to some Windows fundamentals, commands you should have seen before doing the good stuff. This is what this post is about.

Not all stuff in this is DIRECTLY tied to PrivEsc, still it is pretty beneficial to grasp the base concepts.

So let's go, shall we?


Windows Fundamentals

Connecting In

xfreerdp /v:<IP> /u:htb-student /p:<PASSWORD>

RDP gives you a full GUI desktop session on the target, port 3389. This is how you'll connect to most HTB Windows labs aswell (their collection in Academy truly is huge!).
Add +clipboard for copy-paste, /drive:share,/tmp/loot to access your local files from the target.

Knowing Where You Are

Get-WmiObject -Class Win32_OperatingSystem

Tells you the exact Windows version and build number. This matters because exploits are version-specific. CMD equivalent: systeminfo (gives you even more: patches, domain, architecture).

wmic os list brief

Same idea, CMD-style. Quicker output than systeminfo, just OS info.

whoami /user

Shows your username and SID (Security Identifier). The SID is how Windows actually identifies you internally; usernames are just labels. SIDs ending in -500 = built-in Administrator, -501 = Guest. You'll see SIDs everywhere in Windows security.

dir c:\ /a

Like ls -la on Linux. The /a flag shows hidden and system files too, without it you miss things.

tree <directory>
tree c:\ /f | more

Visual directory tree. /f includes files (not just folders). Pipe to more because the output is massive. Useful for quick recon on unfamiliar directories, but in practice you'll use dir more.

Permissions

icacls <path>

The Windows equivalent of getfacl on Linux. Shows the full ACL for a file or folder, who has what access and at what level.

This can be crucial for PrivEsc: you're looking for files or folders where your user has (M)odify or (W)rite access that they shouldn't. Especially on service binaries and directories in PATH.

icacls c:\users /grant joe:f
icacls c:\users /remove joe

Grant/remove permissions. You won't use this offensively often, but understanding the syntax helps you read ACL output.. which you'll do constantly.

Services

Get-Service #PowerShell

Lists all Windows services and their status (Running/Stopped). Services are background processes; many run as SYSTEM. Misconfigured services are one of the most common Windows PrivEsc vectors (unquoted paths, weak binary permissions, writable registry keys).

PowerShell Essentials

help <command>
# or
Get-Help <command> -Full

Like man on Linux. Use it when you don't remember a cmdlet's syntax.

Get-Alias

PowerShell has aliases: ls actually runs Get-ChildItem, cat runs Get-Content, cd runs Set-Location. So your Linux muscle memory partially works in PowerShell. Get-Alias shows the full mapping.

Get-ExecutionPolicy -List
Set-ExecutionPolicy Bypass -Scope Process

PowerShell has a safety feature that blocks script execution by default. Get-ExecutionPolicy shows the current setting. If you can't run a .ps1 script, Set-ExecutionPolicy Bypass -Scope Process disables the restriction for your current session only. You'll need this when running tools like PowerUp or WinPEAS.ps1.

Get-Module | select Name,ExportedCommands | fl

Shows which PowerShell modules are loaded and what commands they provide. Useful to see what's already available on the box (e.g., ActiveDirectory module = domain-joined, interesting).

Security / Defender

Get-MpComputerStatus

Shows Windows Defender status. Is real-time protection on? Are signatures up to date? Check this early. If Defender is active, your tools will get caught. Guides your decision on whether to use on-disk tools or in-memory execution.

reg query <key>

Read values from the Windows Registry (the central config database). You'll use this to check for stored credentials, autostart entries, service configs, and misconfigurations like AlwaysInstallElevated.

Let's test you on what we learned!
tooling check
score: 0 / 0
All right, good start. Now let's go into PrivEsc, shall we?

Tools We'll Be Using

HTB and other sources will be throwing tools in your face like it's nothing. That's good, you absolutely need them for an efficient workflow in boxes, yet that can be quite overwhelming. Here's a simple overview for future reference:

Tool What it does
LaZagne Digs up stored passwords from browsers, databases, Git, chat clients, and more
WES-NG Feed it your systeminfo output and it maps out which vulnerabilities apply to the target
SharpUp C# port of PowerUp; same idea, different runtime
SessionGopher Pulls saved session credentials from PuTTY, WinSCP, FileZilla, RDP, and similar tools
winPEAS Scans for common privesc paths and explains what it finds along the way
Watson Looks for missing patches and ties them to known exploits
Sysinternals Suite We'll be using AccessChk, PipeList, and PsService specifically
JAWS A PowerShell enumeration script built to work even on older PS 2.0 environments
Seatbelt Runs a broad set of local checks; good for getting a quick lay of the land
PowerUp Finds misconfiguration-based privesc vectors and can sometimes exploit them directly

When in need of such, I'll be transferring all of these to the target myself rather than using anything pre-installed.

I'd recommend you do the same. Working out how is left as an exercise for you, on HTB you can always rely on them being in C:\Tools... yet that's too easy, isn't it? Hihi
🌩️
Oh, and don't worry if the following sections throw a lot at you and tips (like the one just below) seem to be placed.. just anywhere haha.
I am simply trying to document what I'm learning, to bring you along and teach you what you need to keep in mind.

LET'S GOOO

A Tool's Safe Haven

Always aim to upload tools to C:\Windows\Temp, the BUILTIN\Users group has write access to it.

Network Enumeration

Spotting Dual-Homed

A host is dual-homed when it has network interfaces connected to two or more different networks.

Think of it as a machine with one foot in the corporate LAN and another in a DMZ or internal subnet you couldn't reach before. For us, that's interesting because compromising it might open a path into a network segment we had no access to.

C:\Users\htb-student>ipconfig /all

Windows IP Configuration

   Host Name . . . . . . . . . . . . : WINLPE-SRV01
   Primary Dns Suffix  . . . . . . . :
   Node Type . . . . . . . . . . . . : Hybrid
   IP Routing Enabled. . . . . . . . : No
   WINS Proxy Enabled. . . . . . . . : No
   DNS Suffix Search List. . . . . . : htb

Ethernet adapter Ethernet1:

   Connection-specific DNS Suffix  . :
   Description . . . . . . . . . . . : vmxnet3 Ethernet Adapter
   Physical Address. . . . . . . . . : 00-50-56-8A-88-7D
   DHCP Enabled. . . . . . . . . . . : No
   Autoconfiguration Enabled . . . . : Yes
   Link-local IPv6 Address . . . . . : fe80::59ba:2624:c975:84c3%2(Preferred)
   IPv4 Address. . . . . . . . . . . : 172.16.20.45(Preferred)
   [...]

Ethernet adapter Ethernet0 2:

   Connection-specific DNS Suffix  . : .htb
   Description . . . . . . . . . . . : vmxnet3 Ethernet Adapter #2
   Physical Address. . . . . . . . . : 00-50-56-8A-B2-0C
   DHCP Enabled. . . . . . . . . . . : Yes
   Autoconfiguration Enabled . . . . : Yes
   IPv6 Address. . . . . . . . . . . : dead:beef::161(Preferred)
   Lease Obtained. . . . . . . . . . : Thursday, April 23, 2026 12:21:33 PM
   Lease Expires . . . . . . . . . . : Thursday, April 23, 2026 1:21:32 PM
   IPv6 Address. . . . . . . . . . . : dead:beef::bdda:e84a:adaa:e490(Preferred)
   Link-local IPv6 Address . . . . . : fe80::bdda:e84a:adaa:e490%4(Preferred)
   IPv4 Address. . . . . . . . . . . : 10.129.64.209(Preferred)
   Subnet Mask . . . . . . . . . . . : 255.255.0.0
   [...]
See that? 2 Network Interface Cards (NICs). They connect a device to a network, they get a MAC address and they can be assigned an IP address.

That's how we know machine is dual-homed, you can see it clearly:

  • Ethernet1172.16.20.45: a private internal network you couldn't reach from outside
  • Ethernet0 210.129.64.209: the HTB network you connected through

Interpreting ARP Output

C:\Users\htb-student>arp -a

Interface: 172.16.20.45 --- 0x2
  Internet Address      Physical Address      Type
  172.16.21.255         ff-ff-ff-ff-ff-ff     static
  224.0.0.22            01-00-5e-00-00-16     static
  224.0.0.252           01-00-5e-00-00-fc     static
  239.255.255.250       01-00-5e-7f-ff-fa     static

Interface: 10.129.64.209 --- 0x4
  Internet Address      Physical Address      Type
  10.129.0.1            00-50-56-8a-95-7b     dynamic
  10.129.50.254         00-50-56-8a-db-a6     dynamic
  10.129.205.123        00-50-56-8a-1a-fd     dynamic
  10.129.255.255        ff-ff-ff-ff-ff-ff     static
  224.0.0.22            01-00-5e-00-00-16     static
  224.0.0.252           01-00-5e-00-00-fc     static
  239.255.255.250       01-00-5e-7f-ff-fa     static
  255.255.255.255       ff-ff-ff-ff-ff-ff     static

The ARP (Address Resolution Protocol) table shows hosts this machine has recently communicated with. Each entry maps an IP address to a MAC address, which is how your machine knows where to actually send packets on the local network.

The Type column tells you how the entry got there.

  • dynamic means the machine actually talked to that host recently and learned its MAC automatically.
  • static entries are either broadcast addresses or multicast groups that are hardcoded by the OS, not real hosts.

So from the output, the only hosts worth paying attention to are the dynamic ones under 10.129.64.209:

  • 10.129.0.1 is the gateway. 10.129.50.254 and 10.129.205.123 are actual hosts that this machine has been talking to, those are interesting.
In a real engagement you'd want to note those down and potentially investigate them for lateral movement after you've escalated privileges.

The 172.16.20.45 interface has no dynamic entries at all, meaning this machine hasn't recently communicated with anyone on that internal network. Doesn't mean nothing is there, just that nothing showed up in the cache.

💡
One thing worth knowing is that ARP entries expire after a while, so the absence of an entry doesn't mean a host doesn't exist. It just means there hasn't been recent traffic to it.

Interpreting the Routing Table

C:\Users\htb-student>route print
===========================================================================
Interface List
  2...00 50 56 8a 88 7d ......vmxnet3 Ethernet Adapter
  4...00 50 56 8a b2 0c ......vmxnet3 Ethernet Adapter #2
  7...00 ff b3 3c cd 5a ......Windscribe VPN
  1...........................Software Loopback Interface 1
  9...00 00 00 00 00 00 00 e0 Microsoft ISATAP Adapter
  6...00 00 00 00 00 00 00 e0 Microsoft ISATAP Adapter #3
===========================================================================

IPv4 Route Table
===========================================================================
Active Routes:
Network Destination        Netmask          Gateway       Interface  Metric
          0.0.0.0          0.0.0.0      172.16.20.1     172.16.20.45    271
          0.0.0.0          0.0.0.0       10.129.0.1    10.129.64.209     15
       10.129.0.0      255.255.0.0         On-link     10.129.64.209    271
    10.129.64.209  255.255.255.255         On-link     10.129.64.209    271
   10.129.255.255  255.255.255.255         On-link     10.129.64.209    271
        127.0.0.0        255.0.0.0         On-link         127.0.0.1    331
        127.0.0.1  255.255.255.255         On-link         127.0.0.1    331
  127.255.255.255  255.255.255.255         On-link         127.0.0.1    331
      172.16.20.0    255.255.254.0         On-link      172.16.20.45    271
     172.16.20.45  255.255.255.255         On-link      172.16.20.45    271
    172.16.21.255  255.255.255.255         On-link      172.16.20.45    271
        224.0.0.0        240.0.0.0         On-link         127.0.0.1    331
        224.0.0.0        240.0.0.0         On-link      172.16.20.45    271
        224.0.0.0        240.0.0.0         On-link     10.129.64.209    271
  255.255.255.255  255.255.255.255         On-link         127.0.0.1    331
  255.255.255.255  255.255.255.255         On-link      172.16.20.45    271
  255.255.255.255  255.255.255.255         On-link     10.129.64.209    271
===========================================================================
Persistent Routes:
  Network Address          Netmask  Gateway Address  Metric
          0.0.0.0          0.0.0.0      172.16.20.1  Default
===========================================================================

IPv6 Route Table
===========================================================================
Active Routes:
 If Metric Network Destination      Gateway
  4    271 ::/0                     fe80::250:56ff:fe8a:957b
  1    331 ::1/128                  On-link
  4    271 dead:beef::/64           On-link
  4    271 dead:beef::161/128       On-link
  4    271 dead:beef::bdda:e84a:adaa:e490/128
                                    On-link
  2    271 fe80::/64                On-link
  4    271 fe80::/64                On-link
  2    271 fe80::59ba:2624:c975:84c3/128
                                    On-link
  4    271 fe80::bdda:e84a:adaa:e490/128
                                    On-link
  1    331 ff00::/8                 On-link
  2    271 ff00::/8                 On-link
  4    271 ff00::/8                 On-link
===========================================================================
Persistent Routes:
  None
💡
The routing table is essentially a decision tree your machine consults every time it wants to send a packet somewhere.

It looks at the destination IP and asks "which rule matches this?" then sends the packet out through the corresponding interface via the specified gateway.

The most important column to understand is Network Destination combined with Netmask.

Together they define which range of IPs a rule applies to. The Gateway column tells the machine where to send the packet next, and Interface tells it which NIC to use to get there.

The two 0.0.0.0 entries at the top are the default routes, these are the catch-all rules that handle any traffic that doesn't match a more specific rule. You have two of them, one per interface.

The Metric column is the tiebreaker; lower wins. So with metric 15, the 10.129.0.1 gateway via 10.129.64.209 takes priority over the 172.16.20.1 one with metric 271. That's why you can reach HTB machines, it's the preferred path out.

The On-link entries don't go through a gateway at all. They mean the destination is directly reachable on that interface without any routing needed: The machine is on the same subnet.

The Persistent Routes section at the bottom is interesting. It shows the 172.16.20.1 default gateway is hardcoded and survives reboots, while the HTB route is only active because DHCP handed it out.
In a real engagement that tells you the 172.16.20.0 network is the machine's permanent home network, the one it was actually configured for.

Checking Windows Defender

C:\Users\htb-student> Get-MpComputerStatus


AMEngineVersion                 : 1.1.18400.4
AMProductVersion                : 4.10.14393.0
AMServiceEnabled                : True
AMServiceVersion                : 4.10.14393.0
AntispywareEnabled              : True
AntispywareSignatureAge         : 1720
AntispywareSignatureLastUpdated : 8/7/2021 11:16:31 AM
AntispywareSignatureVersion     : 1.345.139.0
AntivirusEnabled                : True
AntivirusSignatureAge           : 1720
AntivirusSignatureLastUpdated   : 8/7/2021 11:16:31 AM
AntivirusSignatureVersion       : 1.345.139.0
BehaviorMonitorEnabled          : False
ComputerID                      : 54AF7DE4-3C7E-4DA0-87AC-831B045B9063
ComputerState                   : 0
FullScanAge                     : 4294967295
FullScanEndTime                 :
FullScanStartTime               :
IoavProtectionEnabled           : False
LastFullScanSource              : 0
LastQuickScanSource             : 2
NISEnabled                      : False
NISEngineVersion                : 0.0.0.0
NISSignatureAge                 : 4294967295
NISSignatureLastUpdated         :
NISSignatureVersion             : 0.0.0.0
OnAccessProtectionEnabled       : False
QuickScanAge                    : 0
QuickScanEndTime                : 4/23/2026 12:34:56 PM
QuickScanStartTime              : 4/23/2026 12:31:32 PM
RealTimeProtectionEnabled       : False
RealTimeScanDirection           : 0
PSComputerName                  :

The first thing to look at is RealTimeProtectionEnabled, on this box it's False. That's significant.

Real-time protection is the part of Defender that actively blocks malicious activity as it happens, so with it off, you have a lot more room to move.

Also worth noting: BehaviorMonitorEnabled, IoavProtectionEnabled, NISEnabled, and OnAccessProtectionEnabled are all False.

Combined with signatures last updated in 2021, this machine is essentially running Defender in name only. In a real engagement you wouldn't be this lucky, but knowing how to read this output tells you exactly what you're dealing with before you start dropping tools.

Checking AppLocker

C:\Users\htb-student> Get-AppLockerPolicy -Effective | select -ExpandProperty RuleCollections


PublisherConditions : {*\*\*,0.0.0.0-*}
PublisherExceptions : {}
PathExceptions      : {}
HashExceptions      : {}
Id                  : a9e18c21-ff8f-43cf-b9fc-db40eed693ba
Name                : (Default Rule) All signed packaged apps
Description         : Allows members of the Everyone group to run packaged apps that are signed.
UserOrGroupSid      : S-1-1-0
Action              : Allow

PathConditions      : {%SYSTEM32%\WindowsPowerShell\v1.0\powershell_ise.exe}
PathExceptions      : {}
PublisherExceptions : {}
HashExceptions      : {}
Id                  : 684d8b3e-7656-4451-8abe-2588d772db8f
Name                : Block PowerShell ISE
Description         :
UserOrGroupSid      : S-1-1-0
Action              : Deny

PathConditions      : {%PROGRAMFILES%\*}
PathExceptions      : {}
PublisherExceptions : {}
HashExceptions      : {}
Id                  : 921cc481-6e17-4653-8f75-050b80acca20
Name                : (Default Rule) All files located in the Program Files folder
Description         : Allows members of the Everyone group to run applications that are located in the Program Files
                      folder.
UserOrGroupSid      : S-1-1-0
Action              : Allow

PathConditions      : {c:\windows\system32\cmd.exe}
PathExceptions      : {}
PublisherExceptions : {}
HashExceptions      : {}
Id                  : 9b8293c1-49c7-4bbb-aa17-52c4232b1fe4
Name                : c:\windows\system32\cmd.exe
Description         :
UserOrGroupSid      : S-1-1-0
Action              : Deny

PathConditions      : {%WINDIR%\*}
PathExceptions      : {}
PublisherExceptions : {}
HashExceptions      : {}
Id                  : a61c8b2c-a319-4cd0-9690-d2177cad7b51
Name                : (Default Rule) All files located in the Windows folder
Description         : Allows members of the Everyone group to run applications that are located in the Windows folder.
UserOrGroupSid      : S-1-1-0
Action              : Allow

PathConditions      : {*}
PathExceptions      : {}
PublisherExceptions : {}
HashExceptions      : {}
Id                  : fd686d83-a829-4351-8ff4-27c7de5755d2
Name                : (Default Rule) All files
Description         : Allows members of the local Administrators group to run all applications.
UserOrGroupSid      : S-1-5-32-544
Action              : Allow

PublisherConditions : {*\*\*,0.0.0.0-*}
PublisherExceptions : {}
PathExceptions      : {}
HashExceptions      : {}
Id                  : b7af7102-efde-4369-8a89-7a6a392d1473
Name                : (Default Rule) All digitally signed Windows Installer files
Description         : Allows members of the Everyone group to run digitally signed Windows Installer files.
UserOrGroupSid      : S-1-1-0
Action              : Allow

PathConditions      : {%WINDIR%\Installer\*}
PathExceptions      : {}
PublisherExceptions : {}
HashExceptions      : {}
Id                  : 5b290184-345a-4453-b184-45305f6d9a54
Name                : (Default Rule) All Windows Installer files in %systemdrive%\Windows\Installer
Description         : Allows members of the Everyone group to run all Windows Installer files located in
                      %systemdrive%\Windows\Installer.
UserOrGroupSid      : S-1-1-0
Action              : Allow

PathConditions      : {*.*}
PathExceptions      : {}
PublisherExceptions : {}
HashExceptions      : {}
Id                  : 64ad46ff-0d71-4fa0-a30b-3f3d30c5433d
Name                : (Default Rule) All Windows Installer files
Description         : Allows members of the local Administrators group to run all Windows Installer files.
UserOrGroupSid      : S-1-5-32-544
Action              : Allow

PathConditions      : {%PROGRAMFILES%\*}
PathExceptions      : {}
PublisherExceptions : {}
HashExceptions      : {}
Id                  : 06dce67b-934c-454f-a263-2515c8796a5d
Name                : (Default Rule) All scripts located in the Program Files folder
Description         : Allows members of the Everyone group to run scripts that are located in the Program Files folder.
UserOrGroupSid      : S-1-1-0
Action              : Allow

PathConditions      : {%WINDIR%\*}
PathExceptions      : {}
PublisherExceptions : {}
HashExceptions      : {}
Id                  : 9428c672-5fc3-47f4-808a-a0011f36dd2c
Name                : (Default Rule) All scripts located in the Windows folder
Description         : Allows members of the Everyone group to run scripts that are located in the Windows folder.
UserOrGroupSid      : S-1-1-0
Action              : Allow

PathConditions      : {*}
PathExceptions      : {}
PublisherExceptions : {}
HashExceptions      : {}
Id                  : ed97d0cb-15ff-430f-b82c-8d7832957725
Name                : (Default Rule) All scripts
Description         : Allows members of the local Administrators group to run all scripts.
UserOrGroupSid      : S-1-5-32-544
Action              : Allow

Two rules here stand out immediately: cmd.exe is explicitly denied for Everyone, and so is powershell_ise.exe. So if you only have a standard user shell, you can't just pop open a normal Command Prompt.

However, plain powershell.exe is not blocked, only the ISE variant is. And since everything under %WINDIR%\* and %PROGRAMFILES%\* is allowed, there's already a lot of room to work with.

The key rule to remember: Administrators bypass all of this via the (Default Rule) All files entry scoped to S-1-5-32-544, the local Administrators group. That's your target. Once you're in that group, AppLocker stops being your problem.

Initial Enumeration

I know there's a gazillion cheatsheets out there, but let's first pretend we don't have them. We want to really grasp what we're looking for with each command.

Using tasklist

PS C:\Users\htb-student> tasklist /svc

Image Name                     PID Services
========================= ======== ============================================
System Idle Process              0 N/A
System                           4 N/A
smss.exe                       356 N/A
csrss.exe                      436 N/A
wininit.exe                    540 N/A
csrss.exe                      548 N/A
winlogon.exe                   604 N/A
services.exe                   676 N/A
lsass.exe                      684 KeyIso, SamSs, VaultSvc
svchost.exe                    784 BrokerInfrastructure, DcomLaunch, LSM,
                                   PlugPlay, Power, SystemEventsBroker
svchost.exe                    848 RpcEptMapper, RpcSs
svchost.exe                    960 TermService
svchost.exe                    968 Appinfo, CertPropSvc, DsmSvc, gpsvc,
                                   IKEEXT, iphlpsvc, lfsvc, ProfSvc, Schedule,
                                   SENS, SessionEnv, ShellHWDetection, Themes,
                                   UserManager, Winmgmt, wlidsvc, WpnService,
                                   wuauserv
dwm.exe                       1004 N/A
svchost.exe                    100 Dhcp, EventLog, lmhosts, TimeBrokerSvc
svchost.exe                    108 NcbService, PcaSvc, ScDeviceEnum, StorSvc,
                                   TrkWks, UALSVC, UmRdpService,
                                   WdiSystemHost, wudfsvc
svchost.exe                    888 EventSystem, FontCache, LicenseManager,
                                   netprofm, nsi, W32Time, WinHttpAutoProxySvc
svchost.exe                   1080 BFE, CoreMessagingRegistrar, DPS, MpsSvc
vm3dservice.exe               1120 vm3dservice
svchost.exe                   1196 CryptSvc, Dnscache, LanmanWorkstation,
                                   NlaSvc, WinRM
svchost.exe                   1400 Wcmsvc
svchost.exe                   1476 WlanSvc
svchost.exe                   1844 PolicyAgent
spoolsv.exe                   1924 Spooler
svchost.exe                   1980 AppHostSvc
svchost.exe                   1988 DiagTrack
svchost.exe                   1312 ftpsvc
WindscribeService.exe         2020 WindscribeService
vmtoolsd.exe                  2060 VMTools
FileZilla Server.exe          2076 FileZilla Server
svchost.exe                   2100 StateRepository, tiledatamodelsvc
MsMpEng.exe                   2112 WinDefend
inetinfo.exe                  2120 IISADMIN
VGAuthService.exe             2132 VGAuthService
sqlwriter.exe                 2144 SQLWriter
svchost.exe                   2188 LanmanServer
svchost.exe                   2216 W3SVC, WAS
Tomcat8.exe                   2256 Tomcat8
conhost.exe                   2456 N/A
dllhost.exe                   3356 COMSysApp
sqlservr.exe                  3368 MSSQL$SQLEXPRESS01
sqlceip.exe                   3376 SQLTELEMETRY$SQLEXPRESS01
WmiPrvSE.exe                  3584 N/A
msdtc.exe                     3668 MSDTC
RuntimeBroker.exe             4736 N/A
sihost.exe                    4816 N/A
svchost.exe                   4836 CDPUserSvc_45dd1, OneSyncSvc_45dd1
[...]

We can use the tasklist command to look at running processes.The /svc flag is what makes this useful: it maps each process to the Windows services running inside it, not just the process name.

What to look for

Standard Windows processes like smss.exe, csrss.exe, winlogon.exe, lsass.exe and the army of svchost.exe instances are all normal. Don't let the noise distract you. Your eyes should go straight to anything that isn't a default Windows component.

From my output, the interesting ones are:

  • FileZilla Server.exe running as a service is immediately worth investigating. FTP servers are frequently misconfigured — anonymous access, weak credentials, or sensitive files in accessible directories are all common findings.
  • inetinfo.exe means IIS is running, and svchost.exe hosting W3SVC and WAS confirms an active web server. Web applications running locally are a common privesc vector, they often run as SYSTEM or a privileged service account.
  • Tomcat8.exe is another web server, Java-based this time. Tomcat has a manager interface that's frequently left with default credentials (tomcat:tomcat or admin:admin). If you can log in, you can deploy a WAR file and get code execution.
  • sqlservr.exe means SQL Server Express is running (MSSQL$SQLEXPRESS01). Databases often store credentials, and SQL Server misconfigurations can lead directly to SYSTEM via xp_cmdshell.
  • WindscribeService.exe is a VPN client service — interesting because third-party services like this sometimes have weak permissions on their binaries or service configurations, which is a classic privesc path we'll get into later.
  • MsMpEng.exe is Defender. we already know from earlier that it's essentially toothless on this box, but in a real environment spotting this tells you what evasion you'll need.
tooling check
score: 0 / 0

Displaying Environment Variables (set)

Displaying Environment Variables

set

Quick gotcha: set only works in cmd.exe. In PowerShell, set is aliased to Set-Variable which is why might get an error. Use either of these instead:

# PowerShell equivalents
Get-ChildItem Env:
# or
ls env:

What to look for in the output:

💡
PATH is the most interesting one. If any directory in there is writable by your user, that's a potential privesc path. Also note the order entries on the left take priority over C:\Windows\System32, so a writable custom path on the left is significantly worse than one on the right.

HOMEDRIVE and HOMEPATH tell you where the user's home lives. In enterprise environments this is often a network share rather than a local path, worth navigating to manually, as IT shares occasionally contain credential spreadsheets or other sensitive files.

USERNAME and USERDOMAIN confirm whose context you're running in, and LOGONSERVER tells you which domain controller authenticated the session.

Viewing Config Info

C:\Users\htb-student> systeminfo

Host Name:                 WINLPE-SRV01
OS Name:                   Microsoft Windows Server 2016 Standard
OS Version:                10.0.14393 N/A Build 14393
OS Manufacturer:           Microsoft Corporation
OS Configuration:          Standalone Server
OS Build Type:             Multiprocessor Free
Registered Owner:          Windows User
Registered Organization:
Product ID:                00376-30821-30176-AA890
Original Install Date:     3/24/2021, 3:46:32 PM
System Boot Time:          4/23/2026, 12:21:21 PM
System Manufacturer:       VMware, Inc.
System Model:              VMware7,1
System Type:               x64-based PC
Processor(s):              3 Processor(s) Installed.
                           [01]: AMD64 Family 23 Model 1 Stepping 2 AuthenticAMD ~1996 Mhz
                           [02]: AMD64 Family 23 Model 1 Stepping 2 AuthenticAMD ~1996 Mhz
                           [03]: AMD64 Family 23 Model 1 Stepping 2 AuthenticAMD ~1996 Mhz
BIOS Version:              VMware, Inc. VMW71.00V.24504846.B64.2501180334, 1/18/2025
Windows Directory:         C:\Windows
System Directory:          C:\Windows\system32
Boot Device:               \Device\HarddiskVolume2
System Locale:             en-us;English (United States)
Input Locale:              en-us;English (United States)
Time Zone:                 (UTC-08:00) Pacific Time (US & Canada)
Total Physical Memory:     6,143 MB
Available Physical Memory: 4,127 MB
Virtual Memory: Max Size:  7,167 MB
Virtual Memory: Available: 4,964 MB
Virtual Memory: In Use:    2,203 MB
Page File Location(s):     C:\pagefile.sys
Domain:                    WORKGROUP
Logon Server:              \\WINLPE-SRV01
Hotfix(s):                 4 Hotfix(s) Installed.
                           [01]: KB3199986
                           [02]: KB4054590
                           [03]: KB5001078
                           [04]: KB3200970
Network Card(s):           3 NIC(s) Installed.
                           [01]: vmxnet3 Ethernet Adapter
                                 Connection Name: Ethernet0 2
                                 DHCP Enabled:    Yes
                                 DHCP Server:     10.10.10.2
                                 IP address(es)
                                 [01]: 10.129.64.209
                                 [02]: fe80::bdda:e84a:adaa:e490
                                 [03]: dead:beef::bdda:e84a:adaa:e490
                                 [04]: dead:beef::161
                           [02]: vmxnet3 Ethernet Adapter
                                 Connection Name: Ethernet1
                                 DHCP Enabled:    No
                                 IP address(es)
                                 [01]: 172.16.20.45
                                 [02]: fe80::59ba:2624:c975:84c3
                           [03]: Windscribe VPN
                                 Connection Name: Ethernet
                                 Status:          Media disconnected
Hyper-V Requirements:      A hypervisor has been detected. Features required for Hyper-V will not be displayed.
Damn, what are we bombarded with here? Look at these four things:

Four things, nothing else:

  • OS Version and System Boot Time: together these tell you the patch story. An old build number or a machine that hasn't rebooted in months is likely unpatched and vulnerable to known exploits.
  • Hotfix(s) — only 3 hotfixes installed here, which is almost nothing for a production server. Feed these KB numbers into WES-NG later and it'll map them to known CVEs for you.
  • System Manufacturer / ModelVMware7,1 tells you immediately it's a VM. Useful context for later stages.
  • Network Card(s) — two NICs listed confirms dual-homed, same conclusion we drew from ipconfig /all earlier but this gives it to you in one place without having to parse adapter blocks.

Enumerating Installed Patches

Two ways to get the same info:

C:\Users\htb-student> wmic qfe
Caption                                     CSName        Description      FixComments  HotFixID   InstallDate  Installe
dBy                 InstalledOn  Name  ServicePackInEffect  Status
http://support.microsoft.com/?kbid=3199986  WINLPE-SRV01  Update                        KB3199986               NT AUTHO
RITY\SYSTEM         11/21/2016
http://support.microsoft.com/?kbid=4054590  WINLPE-SRV01  Update                        KB4054590               WINLPE-S
RV01\Administrator  3/30/2021
https://support.microsoft.com/help/5001078  WINLPE-SRV01  Security Update               KB5001078               NT AUTHO
RITY\SYSTEM         3/25/2021
http://support.microsoft.com/?kbid=3200970  WINLPE-SRV01  Security Update               KB3200970               WINLPE-S
RV01\Administrator  4/13/2021
C:\Users\htb-student> Get-HotFix | ft -AutoSize

Source       Description     HotFixID  InstalledBy                InstalledOn
------       -----------     --------  -----------                -----------
WINLPE-SRV01 Update          KB3199986 NT AUTHORITY\SYSTEM        11/21/2016 12:00:00 AM
WINLPE-SRV01 Update          KB4054590 WINLPE-SRV01\Administrator 3/30/2021 12:00:00 AM
WINLPE-SRV01 Security Update KB5001078 NT AUTHORITY\SYSTEM        3/25/2021 12:00:00 AM
WINLPE-SRV01 Security Update KB3200970 WINLPE-SRV01\Administrator 4/13/2021 12:00:00 AM

Get-HotFix is generally cleaner output. Use wmic qfe as a fallback if PowerShell isn't available.

The only columns that matter are HotFixID and InstalledOn. You're looking for two things: how many patches are installed total, and when the most recent one was applied. A handful of KBs and a date from years ago means the machine is likely sitting on unpatched CVEs.

Again: Take those KB numbers and feed them into WES-NG, that's what maps them to actual exploits. We set that tool up earlier for exactly this reason.

Installed Programs

wmic product get name
# or
Get-WmiObject -Class Win32_Product | select Name, Version

wmic product get name is the quick CMD version. The PowerShell equivalent gives you versions too, which matters — knowing something is installed is useful, knowing it's running an old vulnerable version is actionable.

What you're actually looking for here is software that shouldn't be on a server, or software that is on a server and has known CVEs. Java 8 Update 231 in the output above, for instance, is ancient. Old Java, old Tomcat, old SQL Server installs — these are worth cross-referencing with WES-NG or a quick search.

A/lso: if you spot FileZilla, PuTTY, WinSCP, or similar tools, that's your cue to run LaZagne or SessionGopher. Those applications store session credentials locally, and they're frequently forgotten about.

Netstat: What's Listening?

C:\Windows\system32>netstat -ano

Active Connections

  Proto  Local Address          Foreign Address        State           PID
  TCP    0.0.0.0:21             0.0.0.0:0              LISTENING       2068
  TCP    0.0.0.0:80             0.0.0.0:0              LISTENING       4
  TCP    0.0.0.0:135            0.0.0.0:0              LISTENING       860
  TCP    0.0.0.0:445            0.0.0.0:0              LISTENING       4
  TCP    0.0.0.0:1433           0.0.0.0:0              LISTENING       3424
  TCP    0.0.0.0:3389           0.0.0.0:0              LISTENING       988
  [....]

The -ano flags give you everything useful: active connections, listening ports, and the PID of the process behind each one.
Cross-reference the PID column with tasklist /svc to figure out what process owns each port. That's how you connect the dots.

The column that matters most is Local Address. Anything bound to 0.0.0.0 is accessible from outside.
Anything bound to 127.0.0.1 is only reachable locally, meaning you'd have to already be on the box to hit it.

That second category is exactly what you're hunting. A service listening only on localhost is invisible from your attack machine, but once you have a shell, it's right there. Port 1433 (SQL Server) or 8080 (maybe a local web app) bound to loopback is a classic privesc setup: the service is running as SYSTEM but was never meant to be exposed, so nobody hardened it.

User & Group Information

Even on a well-maintained box, you'll often find the path to SYSTEM runs straight through a person. A browsable home directory, a reused password, a forgotten admin account.

Logged-In Users

C:\Windows\system32>query user
 USERNAME              SESSIONNAME        ID  STATE   IDLE TIME  LOGON TIME
 sccm_svc              console             1  Active      none   4/25/2026 12:16 PM
>htb-student           rdp-tcp#0           2  Active          .  4/25/2026 12:17 PM

Shows who's currently on the box and how. The STATE and IDLE TIME columns are what matter operationally: an active session with zero idle time means someone is sitting at that machine right now. During a covert engagement that changes how you move. On a box with an active admin session you want to be quiet: no noisy enumeration tools, no obvious file drops.

The SESSIONNAME column tells you how they connected. rdp-tcp#0 means RDP. console means local. That context matters if you're thinking about session hijacking later.

Current User

C:\Windows\system32>echo %USERNAME%
htb-student

First thing you run after getting a shell. You need to know whose context you're operating in before you do anything else. Sometimes you land directly as SYSTEM or as a service account with powerful privileges. In that case half your work is already done.

Current User Privileges

C:\Windows\system32>whoami /priv

PRIVILEGES INFORMATION
----------------------

Privilege Name                Description                              State
============================= ======================================== ========
SeTakeOwnershipPrivilege      Take ownership of files or other objects Disabled
SeChangeNotifyPrivilege       Bypass traverse checking                 Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set           Disabled

This is one of the most important commands in your initial enumeration. Certain privileges are direct privesc paths regardless of group membership. A few important examples to know by heart:

  • SeImpersonatePrivilege: held by service accounts, exploitable via Juicy Potato, PrintSpoofer, or similar tools to get SYSTEM almost immediately.
  • SeBackupPrivilege: lets you read any file on the system regardless of ACLs. That includes SAM, SYSTEM, and NTDS.dit.
  • SeDebugPrivilege: lets you inject into and read memory of processes you don't own, including lsass.
  • SeLoadDriverPrivilege: lets you load kernel drivers, which means kernel-level code execution.
Even a Disabled state doesn't protect you here. Most of these can be enabled in the same process with a few API calls.

Current User Group Membership

C:\Windows\system32>whoami /groups

GROUP INFORMATION
-----------------

Group Name                           Type             SID          Attributes
==================================== ================ ============ ==================================================
Everyone                             Well-known group S-1-1-0      Mandatory group, Enabled by default, Enabled group
BUILTIN\Remote Desktop Users         Alias            S-1-5-32-555 Mandatory group, Enabled by default, Enabled group
BUILTIN\Users                        Alias            S-1-5-32-545 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\INTERACTIVE             Well-known group S-1-5-4      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\Local account           Well-known group S-1-5-113    Mandatory group, Enabled by default, Enabled group
LOCAL                                Well-known group S-1-2-0      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\High Mandatory Level Label            S-1-16-12288

Group membership is how Windows delegates rights, and inherited rights are easy to overlook. What you're scanning for here is anything that isn't standard for a normal user account: membership in Backup Operators, Event Log Readers, Remote Management Users, DnsAdmins, or Hyper-V Administrators all have documented privesc paths.

The Mandatory Label line at the bottom tells you your integrity level. Medium is a standard user. High means elevated. System means you're already there.

All Local Users

C:\Windows\system32>net user

User accounts for \\WINLPE-SRV01

-------------------------------------------------------------------------------
Administrator            DefaultAccount           Guest
helpdesk                 htb-student              htb-student_adm
jordan                   logger                   mrb3n
sarah                    sccm_svc                 secsvc
sql_dev
The command completed successfully.

Gives you the full picture of who has an account on this box. Look for anything non-standard alongside the built-in accounts. Naming patterns like bob and bob_adm side by side are a credential reuse gift. Service account names often reveal what software is installed. Accounts like secsvc or helpdesk suggest IT staff with elevated access. Worth investigating whether their profile directories are readable.

All Local Groups

C:\Windows\system32>net localgroup

Aliases for \\WINLPE-SRV01

-------------------------------------------------------------------------------
*Access Control Assistance Operators
*Administrators
*Backup Operators
*Certificate Service DCOM Access
*Cryptographic Operators
*Distributed COM Users
*Event Log Readers
*Guests
*Hyper-V Administrators
*IIS_IUSRS
[...]

The default groups are noise. What you want to notice is anything custom; a group named after a department, a project, or a specific application. Non-standard groups sometimes exist purely to grant access to something sensitive, and their membership is often poorly maintained.

Also worth paying attention to: Remote Desktop Users, Remote Management Users (WinRM), and Backup Operators. These are default groups but non-default membership is a flag.

Group Details

net localgroup "Group Name"
Run this for any group that looks interesting, but always run it for administrators. You're looking for accounts that shouldn't be there: service accounts, regular user accounts, or domain groups that have been lazily added. Any of those is potentially a lateral movement path.

Don't skip the Comment field on custom groups either. It sounds unlikely but credentials in group descriptions are a real finding.

Password Policy

C:\Windows\system32>net accounts
Force user logoff how long after time expires?:       Never
Minimum password age (days):                          0
Maximum password age (days):                          Unlimited
Minimum password length:                              0
Length of password history maintained:                None
Lockout threshold:                                    Never
Lockout duration (minutes):                           30
Lockout observation window (minutes):                 30
Computer role:                                        SERVER
The command completed successfully.

The password policy tells you what you're up against before you start any credential attacks. The fields that matter:

  • Minimum password length: 0 means passwords aren't enforced to meet any complexity bar. Short or blank passwords are possible.
  • Lockout threshold: Never means you can brute force local accounts without risk of locking anyone out. That's significant.
  • Maximum password age tells you how stale credentials can get. 42 days is standard, but if you see Never that means passwords may not have been rotated in years.
  • Computer role: SERVER confirms this isn't a workstation — it's worth noting for context.

And a third time: Check what you've learned!

tooling check
score: 0 / 0
That was quite a lot now wasn't it? We've covered maany commands that you can initially do to figure out what's going on. Next time we will go into Processes and user privileges more. See you then!
Subscribe to my monthly newsletter

No spam, no sharing to third party. Only you and me.

Member discussion