Please don’t misunderstand me, you really need Powershell and all it’s magic if you are a pentester, don’t you?

But what can you do if some policy is blocking  access to powershell.exe?  Yes, this is a well known problem and there are many solutions. In my article I just want to focus on a quick & dirty bypass. The idea is to have e C# assembly  which will execute our powershell scripts. Nothing new, of course 😉

First of all, why don’t we need powershell.exe for executing our .ps1 scripts?

Because powershell scripting, just like C#,  is only a “frontend” to the .Net Framework , they are just languages.

In C#, you need to compile the  programs  in order to execute them, unlike Powershell scripts which are interpreted by Powershell.exe

Given that  Powershell.exe is  only an  interpreter for the .NET assembly “System.Management.Automation” ,  it should be possible to interact with this object in our C# program and execute .ps1 scripts.

That’s exactly what the following code does:

 

using System.Collections.ObjectModel; 
using System.Management.Automation; 
using System.Management.Automation.Runspaces; 
using System.IO;
using System;
using System.Text;
namespace PSLess
{
 class PSLess
 {
   static void Main(string[] args)
   {
     if(args.Length ==0)
         Environment.Exit(1);
     string script=LoadScript(args[0]);
     string s=RunScript(script);
     Console.WriteLine(s);
     Console.ReadKey();
   }
 private static string LoadScript(string filename) 
 { 
   string buffer ="";
   try {
    buffer = File.ReadAllText(filename);
    }
   catch (Exception e) 
   { 
     Console.WriteLine(e.Message);
     Environment.Exit(2);
    }
  return buffer;
 }
 private static string RunScript(string script) 
 { 
    Runspace MyRunspace = RunspaceFactory.CreateRunspace();
    MyRunspace.Open();
    Pipeline MyPipeline = MyRunspace.CreatePipeline(); 
    MyPipeline.Commands.AddScript(script);
    MyPipeline.Commands.Add("Out-String");
    Collection<PSObject> outputs = MyPipeline.Invoke();
    MyRunspace.Close();
   StringBuilder sb = new StringBuilder(); 
   foreach (PSObject pobject in outputs) 
   { 
       sb.AppendLine(pobject.ToString()); 
   }
    return sb.ToString(); 
  }
 }
}

The RunScript() method creates first of all  a “runspace”.

Think it as an  isolated instance of the powershell runtime.

Then, we will add our script to the newly created pipeline, sort of communication channel,  and  execute our script commands via the Invoke() method.

Result will be appended to our string builder and returned as a string to our calling function for being displayed to console output. That’s why we added “Out-String” to our commands.

Very simple, do you agree?

Time to compile it and test it!

C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe
/reference:
C:\Windows\Microsoft.NET\assembly\GAC_MSIL\System.Management.Automation\v4.0_3.0.0.0__31bf3856ad364e35\system.management.automation.dll 
/out:c:\setup\powerless.exe c:\scripts\powersless.cs

 

Keep in mind that location may vary depending on the  framework versions installed on your system. Also remember to add  reference to the “system.management.automation.dll” assembly.

If everything worked, you should have your compiled  powerless assembly. Create a simple test script:

test.ps1:
echo "Hello from powershell-less"
echo "PID: $pid"

And launch it:

powerless

 

It worked! Just calling a script from our exe without powershell.exe!

This is a very simple script, things could be more complicated if you had to handle also user input and so on, but for the most part of activities where you need powershell this won’t be he case.

In next article we will try other tricks to bypass protections, stay tuned!

That’s all 😉

 

Leave a comment