Environment Variable Attack (PATH / PATHEXT)
Environment Variable Attack
Making a higher-privileged process resolve and run your executable by
polluting the name-resolution it depends on: the PATH and PATHEXT
environment variables. When an elevated shell (or a service, or a
scheduled task) runs a command without a full path
— net user, whoami, python script.py — Windows finds the executable by
searching the directories in PATH, trying the extensions in PATHEXT
in order. If a directory you can write to appears in that search before the
real binary’s directory, you drop a file of the same name and the elevated
context runs your code.
This is the executable sibling of dll-hijacking-sideloading (which is the DLL search order). Same “right name in a writable, higher-priority directory” idea; different variable, different file type.
The two variables
PATH— the ordered list of directories searched for an executable when a command has no directory component. First match wins. A writable directory early inPATHis the hole.PATHEXT— the ordered list of extensions tried when the command has none (default.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.CPL;…). This is what lets a.bat/.cmdyou drop satisfy a call tonet— the shell triesnet.COM,net.EXE,net.BAT, … and runs the first it finds.
The classic: drop net.exe (or net.bat) where PATH looks first
The canonical demonstration, and still a real finding:
- An elevated/admin context runs a bare command, e.g.
net localgrouporwhoami— resolved viaPATH, notC:\Windows\System32\net.exe. - A writable directory appears in
PATHbeforeSystem32(e.g.C:\,C:\Users\Public, a user-writable folder an admin session inherits). - You drop
net.bat(your payload, via thePATHEXTextension trick) ornet.exein that writable directory. - Next time the elevated context runs
net …, it resolves your file first → code execution at that elevated privilege.
:: the recon — what will the elevated context actually resolve?
echo %PATH%
echo %PATHEXT%
:: find a writable dir in %PATH% that precedes System32, then:
echo <your command> > C:\Users\Public\net.bat
:: (or a real net.exe you compiled) — next elevated `net ...` runs it
The PATHEXT angle is the quiet one: a .bat needs no compiler and no
PE signature, and a .bat/.cmd executing in a high-integrity context is
exactly what the box’s own admin scripts do, so it’s easy to miss.
Where the elevated context comes from
The attack needs a higher-priv process that resolves bare commands. Sources:
- An admin’s interactive/elevated shell (UAC-elevated, or a remote admin).
- A service or task whose action is a bare command / script (see the task page’s “script/interpreter” vector — it leans directly on this).
- A logon script / GPO-pushed command that runs as a user with a polluted
inherited
PATH.
The environment-variable attack is the mechanism; the service/task/logon script is the elevated consumer you’re feeding.
Tooling
- winpeas — flags
PATH/PATHEXTattack surface (writable dir inPATH, thePATHEXTextension set). - PowerUp (
Invoke-PathHijack/ the PATH checks) — the PowerShell audit + the drop. - Manual —
echo %PATH%, find the writable prefix, drop the file. The quietest (no tool name on disk).
Red-team notes (OPSEC)
.batover.exe— a droppednet.batleaves no PE, no hash, no signature question. Use it unless the consumer specifically wants an.exe.- Match the exact command the elevated context runs — if it runs
net localgroup, your file must be namednet.*, notnetlocalgroup.*. Get the bare command name from the consumer (the service/task action, the admin’s habit), not a guess. - First-match is the whole game — if
System32precedes your writable dir inPATH, the realnet.exewins and your drop is inert. Confirm the order, not just membership. - It’s a time bomb you arm — your file sits there until the elevated context
next runs the command. Know the trigger (logon, task schedule, the admin’s
next
netcall) or you’ll wait.
Detection
- A high-integrity process running a
.bat/.cmdfrom a user-writable or non-system directory (Sysmon 1ImagePath+ the parent; 4688). PATH/PATHEXTchange — an environment mutation that inserts a writable directory (Event 4688 command line / a process whosePATHdiffers from baseline).- The resolution anomaly — an elevated
net/whoami/pythonwhose resolvedImagePathis notSystem32(the tell that a writable prefix won the search). - A new
*.bat/*.exein a%PATH%dir with a recent timestamp that an elevated process then executes.
Links
- dll-hijacking-sideloading — the DLL-search-order sibling
- service-privesc — an elevated service that resolves bare commands
- scheduled-task-abuse — a task action that’s a bare script/command
- windows-privilege-escalation — the hub
- winpeas — the enumeration that flags this