3 little secrets of netsh.exe

It is typical for many of us to discover ‘the cool thing’, and then quickly move on to research something else. Over the last few years my ‘little known secrets’ series exploited this phenomenon by showcasing scenarios that, admittedly, were available to many researchers before me, all of them ‘who were there first’, but… who then just stopped looking at other interesting things after they discovered, and then published about, ‘that one cool thing’.

if it sounds cryptic…

Take netsh.exe as an example.

Its Lolbas page describes only one lolbin usage that relies on the ‘netsh.exe add‘ command in which we load an arbitrary DLL into netsh.exe process.

O-kay.

A casual study of netsh.exe command line syntax offers two additional opportunities:

  • -f <scriptfile>
  • exec <scriptfile>

These commands take a script name as an input and then process the commands stored inside the <scriptfile> file. It’s super basic, but it works.

And it’s not the end.

Turns out the Alias file processing works too:

  • -a <AliasFile>

And it’s not the end either.

Just trying to add a single alias leads to a DLL loading too! (and I don’t even know if this is a proper syntax!)

And then it hits you…

You are doing all these tests on the very same system, one by one, in a context of changes you have already introduced to the system. And these changes should not be ignored!

The first test added a netsh.exe ‘plug-in’ to the Registry:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NetSh\test=test.dll

As a result, any subsequent invocations of netsh.exe attempted to load that test.dll!

Ouch.

It’s a classic example of contamination of the evidence/sample, and once it happens (and we miss it!), everything that follows, research-wise, is all wrong!

And this is the moment when we come back to the basics, and test our hypothesis one by one, using _clean_ environment for all the tests we have ever thought of.

And then, after careful testing, we can still prove that these are still very decent LOLBIN scenarios;

  • -f <scriptfile>
  • exec <scriptfile>
  • -a <AliasFile>

And if you enter the interactive mode of netsh.exe, you can add a DLL-loading alias like this, too:

or

The lesson here is that we always need to dig a bit more, but we also need to be careful, because some of our conclusions may be convenient, but also… incorrect…

1 little known secret of ShellExec_RunDLL

The ShellExec_RunDLL API is now exposed by both shell32.dll and windows.storage.dll.

It is not the only curiosity about this function. Analysing its code one can discover that is accepts a secret command line argument.

If we provide a question mark in the command line argument, the function will interpret the string that follows the question mark as a number. It will then convert that numerical value into a number using StrToIntExW with a STIF_SUPPORT_HEX flag (accepts either decimal or hexadecimal number), and then add that value to 0x100 (SEE_MASK_NOASYNC/SEE_MASK_FLAG_DDEWAIT). Finally, use the resulting total to set the SHELLEXECUTEINFO.fMask value passed to ShellExecuteEx. The function then searches for the second question mark and then uses the position following that question mark as a place where the actual command line passed to ShellExecuteEx starts:

If it sounds too complicated, the basic idea is that function can be invoked in 2 modes:

  • regular invocation
shell32.dll, ShellExec_RunDLL <cmd line argument>
windows.storage.dll, ShellExec_RunDLL <cmd line argument>
  • invocation that modifies fmask
shell32.dll, ShellExec_RunDLL <?fmaskvalue?> <cmd line argument> 
windows.storage.dll, ShellExec_RunDLL <?fmaskvalue?> <cmd line argument>

f.ex.:

ShellExec_RunDLL ?100?calc.exe

And if you are looking for a better example:

ShellExec_RunDLL ?0x00800000?<file>

can be used to bypass Zone.Identifier checks (0x00800000 = SEE_MASK_NOZONECHECKS) for the executed file.

Since the parsing of the fmask value is done with a code that allows for many different inputs, many interesting invocations are possible:

ShellExec_RunDLL ?100?calc.exe
ShellExec_RunDLL ? 100 ?calc.exe
ShellExec_RunDLL ? 0x100 0x200 ?calc.exe
ShellExec_RunDLL ?0x100 notepad.exe?calc.exe
ShellExec_RunDLL ?0x100 format c: ?calc.exe
ShellExec_RunDLL ?0x100 https://google.com ?calc.exe
ShellExec_RunDLL ?0x100 c:\programdata\malware\calc.exe ?calc.exe

Every single one of them will launch Calculator.