Active Directory 列舉 - 手動與自動
Active Directory 列舉 - 手動與自動
Normal User : stephanie (Member of Remote Desktop Group)
Domain FQDN : corp.com
Client : Windows 11
機器 IP
192.168.45.168 kali
192.168.208.70 dc1
192.168.208.72 web04
192.168.208.73 files04
192.168.208.74 client74
192.168.208.75 client75
192.168.208.76 client76
一開始使用網域帳號 Stephanie / LegmanTeamBenzoin! RDP 登入到 Client 75
└─$ xfreerdp /u:stephanie /d:corp.com /v:192.168.208.75
反覆測試後要加上忽略憑證,以及密碼直接帶入,但因為密碼有兩個驚嘆號,所以加上單引號
└─$ xfreerdp /u:stephanie /p:'LegmanTeamBenzoin!!' /d:corp.com /v:192.168.208.75 /cert:ignore
net user /domain 列舉網域的使用者帳號
管理者通常喜歡在帳號的前面或是後面加上 admin 的字眼,所以從上圖中我們首先接著列舉使用者帳號 jeffadmin,net user jeffadmin /domain
結果馬上中獎是 Domain Admins 群組成員
列舉網域的群組, net group /domain
透過 net 指令列舉特定網域群組 "Sales Department"
指令 net group "Sales Department" /domain
管理部門的使用者 net group "Management Department" /domain,只有 jen 一個帳號
練習題的 flag 藏在列舉網域群組中
使用 PowerShell 和 .NET 類別列舉 Active Directory
LDAP 路徑的原型 LDAP://HostName[:PortNumber][/DistinguishedName]
完整的 LDAP 路徑需要三個參數:HostName、 PortNumber、DistinguishedName
Powershell 簡單列舉 Domain 腳色指令,一般使用者都可以列舉
[System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
我們將上述的指令改成參數並寫入到一個 *.ps1 檔案中如下
在 powershell 編輯器下可以直接看到輸出的結果與上圖一樣
放在該使用者桌面取名為 enumeration.ps1
存檔後讓我們直接執行該檔案再測試一次,結果 GG,主要錯誤顯示
cannot be loaded because running scripts is disabled on this system
故要先執行繞過執行策略 powershell -ep bypass 再執行一次該檔案,無問題地輸出
從輸出的結果可以看到 PdcRoleOwner 是 DC1.corp.com
PDC 的主機名是我們需要的,由於 LDAP 路徑需要 PdcRoleOwner 屬性中的主機名,因此我們可以直接從網域物件中提取名稱。如果我們稍後在腳本中需要來自域物件的更多信息,我們將暫時保留 $domainObj並創建一個名為 $PDC 的新變量,該變量將從 $domainObj 變量中保存的 PdcRoleOwner 屬性中提取值 "DC1.corp.com",作法如下
# Store the domain object in the $domainObj variable
$domainObj = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
# Store the PdcRoleOwner name to the $PDC variable
$PDC = $domainObj.PdcRoleOwner.Name
# Print the $PDC variable
$PDC
再執行一次 enumeration.ps1,結果正確無誤地顯示出 PDC 的 Hostname
LDAP 第三個參數是 DN,所以接下來要透過腳本自動提取 DN
可以使用 ([adsi]'').distinguishedName,正確顯示 DC=corp,DC=com
一樣將 DN 變成為一個變數,將剛剛的腳本修改如下並打印出 DN 查看是否正確
# Store the domain object in the $domainObj variable
$domainObj = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
# Store the PdcRoleOwner name to the $PDC variable
$PDC = $domainObj.PdcRoleOwner.Name
# Store the Distinguished Name variable into the $DN variable
$DN = ([adsi]'').distinguishedName
# Print the $DN variable
$DN
有了主機名與 DN 可以直接寫成我們要的 LDAP 腳本了如下
$PDC = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain().PdcRoleOwner.Name
$DN = ([adsi]'').distinguishedName
$LDAP = "LDAP://$PDC/$DN"
$LDAP
新增了 $direntry 變量,它封裝了我們獲得的 LDAP 路徑
$dirsearcher 變數包含 $direntry 變量,並使用該資訊作為 SearchRoot
指向 DirectorySearcher 將運行 FindAll() 方法的層次結構如下
$PDC = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain().PdcRoleOwner.Name
$DN = ([adsi]'').distinguishedName
$LDAP = "LDAP://$PDC/$DN"
$direntry = New-Object System.DirectoryServices.DirectoryEntry($LDAP)
$dirsearcher = New-Object System.DirectoryServices.DirectorySearcher($direntry)
$dirsearcher.FindAll()
接著設定 $dirsearcher.filter 進行過濾
並指定過濾條件為 "samAccountType=805306368"
將枚舉域中的所有使用者
$PDC = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain().PdcRoleOwner.Name
$DN = ([adsi]'').distinguishedName
$LDAP = "LDAP://$PDC/$DN"
$direntry = New-Object System.DirectoryServices.DirectoryEntry($LDAP)
$dirsearcher = New-Object System.DirectoryServices.DirectorySearcher($direntry)
$dirsearcher.filter="samAccountType=805306368"
$dirsearcher.FindAll()
接著新增 foreach 迴圈列出每一個帳號屬性 Properties
這個完整的腳本將搜尋 AD 並根據我們選擇的 samAccountType 過濾結果
然後將結果放入新的 $result 變數中。然後它將根據兩個 foreach 循環進一步過濾結果
第一個循環將提取儲存在 $result 中的物件並將它們放入 $obj變數中
第二個循環將提取每個物件的所有屬性並將資訊儲存在 $prop 變數中
然後該腳本將列印 $prop 並在終端中顯示輸出
然後讓每個帳號透過 ------------------------------- 來區隔與好讀
$domainObj = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
$PDC = $domainObj.PdcRoleOwner.Name
$DN = ([adsi]'').distinguishedName
$LDAP = "LDAP://$PDC/$DN"
$direntry = New-Object System.DirectoryServices.DirectoryEntry($LDAP)
$dirsearcher = New-Object System.DirectoryServices.DirectorySearcher($direntry)
$dirsearcher.filter="samAccountType=805306368"
$result = $dirsearcher.FindAll()
Foreach($obj in $result)
{
Foreach($prop in $obj.Properties)
{
$prop
}
Write-Host "-------------------------------"
}
在輸出的帳號中很多,其中有一個名稱是 jeffadmin,我們對他特別有興趣
所以接下來要做的跟上面一樣,只是輸出時過濾僅輸出帳號是 jeffadmin 這個帳號的相關群組
首先更改了過濾器以使用 name 屬性僅顯示 jeffadmin 的資訊
此外將 .memberof 新增至 $prop 變量,用以僅顯示 jeffadmin 所屬的群組
$domainObj = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
$PDC = $domainObj.PdcRoleOwner.Name
$DN = ([adsi]'').distinguishedName
$LDAP = "LDAP://$PDC/$DN"
$direntry = New-Object System.DirectoryServices.DirectoryEntry($LDAP)
$dirsearcher = New-Object System.DirectoryServices.DirectorySearcher($direntry)
$dirsearcher.filter="name=jeffadmin"
$result = $dirsearcher.FindAll()
Foreach($obj in $result)
{
Foreach($prop in $obj.Properties)
{
$prop.memberof
}
Write-Host "-------------------------------"
}
可以看到他是 Domain Admin
為了使腳本更加靈活,允許我們透過命令列添加所需的參數
例如,我們可以讓腳本接受我們希望列舉的 samAccountType 作為命令列參數
在最頂部,我們使用我們選擇的名稱宣告函數本身,在本例中為 LDAPSearch
然後動態取得所需的 LDAP 路徑連接字串並將其新增至 $DirectoryEntry 變數
然後 DirectoryEntry 和我們的 $LDAPQuery 參數被輸入到 DirectorySearcher 中
最後執行搜尋並將輸出新增到一個陣列中,該陣列根據我們的需要顯示在我們的終端中
function LDAPSearch {
param (
[string]$LDAPQuery
)
$PDC = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain().PdcRoleOwner.Name
$DistinguishedName = ([adsi]'').distinguishedName
$DirectoryEntry = New-Object System.DirectoryServices.DirectoryEntry("LDAP://$PDC/$DistinguishedName")
$DirectorySearcher = New-Object System.DirectoryServices.DirectorySearcher($DirectoryEntry, $LDAPQuery)
return $DirectorySearcher.FindAll()
}
將上述函數存檔為 function.ps1 要使用該函數,我們將其導入記憶體
Import-Module .\function.ps1
在 PowerShell 中,現在可以使用 LDAPSearch 命令(我們聲明的函數名稱)從 AD 獲取資訊
也可以直接搜尋 Object Class,它是定義物件類型的 AD 元件
使用 objectClass=group 來列出網域中的所有群組
要枚舉域中可用的每個群組並顯示使用者成員,我們可以將輸出透過管道傳輸到一個新變數中
並使用 foreach 循環來列印群組的每個屬性。這允許我們選擇我們感興趣的特定屬性。
例如專注於 CN 和 member 屬性
foreach ($group in $(LDAPSearch -LDAPQuery "(objectCategory=group)")) {$group.properties | select {$_.cn}, {$_.member}}
列舉出的群組中 Sales Department 中的成員包含 Development Department
透過之前寫好的 LDAPSearch 單獨列舉出 Sales Department 再次確認一次
先做一個變數為 $sales 為 LDAPSearch 依據 Sales Department 的群組輸出
然後接著輸出 $sales 裡面的 member 屬性
$sales = LDAPSearch -LDAPQuery "(&(objectCategory=group)(cn=Sales Department))"
$sales.properties.member
可以看到確實包含了 Development Department
以同樣的手法這次查看 Development Department 的群組成員,使用 $dev 為變數
$dev = LDAPSearch -LDAPQuery "(&(objectCategory=group)(cn=Development Department*))"
$dev.properties.member
這次出現了管理部門為群組成員
再次以同樣的手法這次查看 Management Department 的群組成員,使用 $manage 為變數
$manage = LDAPSearch -LDAPQuery "(&(objectCategory=group)(cn=Management Department*))"
$manage.properties.member
看到僅剩一個 jen 一般使用者,但這個使用者權限是很大的因為它屬於管理部門群組
管理部門群組又屬於開發部門群組,開發部門群組又隸屬業務部門群組
所以該帳號擁有三個群組所擁有的權限
練習
使用新開發的 PowerShell 腳本列舉網域群組,從Service Personnel開始。解開嵌套群組,然後列舉嵌套群組的最後一個直接使用者成員的屬性以獲得標誌。
同樣手法(注意腳本不能放在桌面否則匯入 Module 會失敗)
$group = LDAPSearch -LDAPQuery "(&(objectCategory=group)(cn=Service Personnel))"
$group.properties.member
發現使用者 Billing
繼續列舉
$group = LDAPSearch -LDAPQuery "(&(objectCategory=group)(cn=Billing))"
$group.properties.member
繼續
$group = LDAPSearch -LDAPQuery "(&(objectCategory=group)(cn=Customer support))"
$group.properties.member
順便 net user /domain 確認 michelle 是使用者物件了
enumeration.ps1 改成該使用者 michelle
run 就拿到 flag 了
留言
張貼留言