Sunday, November 16, 2008

Running commands as SYSTEM from VBA in Word or Excel

Sometime's it is useful to run commands with SYSTEM level privilege because, for some reason, simply having Administrator won't allow you to do something you need. I often run into this with trying to kill antivirus processes or similar, as they usually require some sort of password to shut them off. If you kill it from under the SYSTEM account, however, it'll shut off without any problems:

Function Run_Sys_Cmds(arrayCmds As Variant, visibility, wait_on_execute)

Set fso = CreateObject("Scripting.FileSystemObject")
Set systemCmd = fso.CreateTextFile(Environ("TEMP") & "\systemCmd.vbs")
Set batchRun = fso.CreateTextFile(Environ("TEMP") & "\systemBatch.bat")

systemCmd.WriteLine ("CreateObject(""Wscript.Shell"").Run """ & Environ("TEMP") & "\systemBatch.bat" & """, " & visibility & ", " & wait_on_execute)

For Each cmd In arrayCmds
batchRun.WriteLine (cmd)
Next cmd


Run_Cmd "sc create systemCmd binpath= ""%COMSPEC% /c wscript %TEMP%\systemCmd.vbs "" type= own type= interact", INVISIBLE, WAIT
Run_Cmd "sc start systemCmd", INVISIBLE, WAIT
Run_Cmd "sc delete systemCmd", INVISIBLE, WAIT
Kill Environ("TEMP") & "\systemCmd.vbs"
Kill Environ("TEMP") & "\systemBatch.bat"

End Function

This version only accepts an array of commands to be processed. I found that it was way too slow to process a large number of commands unless you did it this way. It would be simple to modify to accept a regular String instead, if you wish to change it to use it for one-off commands.

You'd call this with something like:
    Dim syscmd(1) As String
syscmd(0) = "set && pause"
syscmd(1) = "ping"
Run_Sys_Cmds syscmd, VISIBLE, WAIT

It executes commands at the SYSTEM level by creating a service that will run your command for you. Unless you specify otherwise, services always run as the SYSTEM account. Creating services is only possible if you have Administrator-level privileges on the system, so I really only find this useful to get around locked files or antivirus.

It's on my TO DO list to play with the token-kidnapping exploit for Windows Server 2003/2008 (and supposedly XP2?) that allows any authenticated user to gain SYSTEM privileges. Unfortunately, I haven't had time to play with it yet.


Justin Parr said...

You can also do this with an unprotected scheduler:

for /f "usebackq tokens=9" %i in ( `at 1:00 /interactive c:\windows\system32\cmd.exe /k` ) do (
schtasks /run /tn at%i
at %i /d

(if you run this from a batch file, change %i to %%i)

This will cause a "superprompt" to appear (except on Vista, because Vista sucks)

On Vista, you can do the same thing using NetCat. Instead of a command prompt, execute:

nc -L -e c:\windows\system32\cmd.exe -p 1234

This will cause the scheduler to launch netcat, which will spawn a command prompt when you telnet to the machine on port 1234.

Have fun....


Anonymous said...


brilliant code! Thank you!

Question: is it possible to stop the sequence of syscmds (0,1,...) and interact with the SYSTEM shell and close it afterwards with a combination of keyboard-strokes?

greetings from Switzerland

Nathan Keltner said...


Sure. I have created a service on my machine to launch a system shell whenever I happen to need one.

You create the service with:
C:\>sc create syscmd binpath= "%COMSPEC% /c start" type= own type= interact
[SC] CreateService SUCCESS

Then, whenever you need a system shell:

C:\>sc start syscmd
[SC] StartService FAILED 1053:

The service did not respond to the start or control request in a timely fashion.

... and a new SYSTEM level shell pops up on screen.