hacktricks/pentesting-web/browser-extension-pentesting-methodology
2024-06-08 12:13:26 +00:00
..
browext-clickjacking.md Translated ['README.md', 'binary-exploitation/arbitrary-write-2-exec/aw2 2024-05-05 22:46:17 +00:00
browext-permissions-and-host_permissions.md Translated ['README.md', 'binary-exploitation/arbitrary-write-2-exec/aw2 2024-05-05 22:46:17 +00:00
browext-xss-example.md Translated to Korean 2024-02-10 21:30:13 +00:00
README.md Translated ['pentesting-web/browser-extension-pentesting-methodology/REA 2024-06-08 12:13:26 +00:00

브라우저 익스텐션 펜테스팅 방법론

htARTE (HackTricks AWS Red Team Expert)를 통해 제로부터 영웅이 되는 AWS 해킹을 배우세요 htARTE (HackTricks AWS Red Team Expert)!

HackTricks를 지원하는 다른 방법:

기본 정보

브라우저 익스텐션은 JavaScript로 작성되며 브라우저에 의해 백그라운드에서 로드됩니다. DOM을 가지고 있지만 다른 사이트의 DOM과 상호작용할 수 있습니다. 이는 다른 사이트의 기밀성, 무결성 및 가용성(CIA)을 침해할 수 있음을 의미합니다.

주요 구성 요소

익스텐션 레이아웃은 시각화되었을 때 가장 잘 보이며 세 가지 구성 요소로 구성됩니다. 각 구성 요소를 자세히 살펴보겠습니다.

http://webblaze.cs.berkeley.edu/papers/Extensions.pdf

콘텐츠 스크립트

각 콘텐츠 스크립트는 단일 웹 페이지의 DOM에 직접 액세스할 수 있으며 잠재적으로 악의적인 입력에 노출됩니다. 그러나 콘텐츠 스크립트에는 확장 기능 코어로 메시지를 보낼 수 있는 능력 외에는 권한이 없습니다.

익스텐션 코어

익스텐션 코어에는 대부분의 익스텐션 권한/액세스가 포함되어 있지만, 익스텐션 코어는 XMLHttpRequest 및 콘텐츠 스크립트를 통해 웹 콘텐츠와 상호작용할 수 있습니다. 또한 익스텐션 코어는 호스트 머신에 직접 액세스할 수 없습니다.

네이티브 바이너리

익스텐션은 사용자의 전체 권한을 가진 호스트 머신에 액세스할 수 있는 네이티브 바이너리를 허용합니다. 네이티브 바이너리는 플래시 및 기타 브라우저 플러그인에서 사용되는 표준 넷스케이프 플러그인 응용 프로그램 프로그래밍 인터페이스(NPAPI)를 통해 익스텐션 코어와 상호작용합니다.

경계

{% hint style="danger" %} 사용자의 전체 권한을 얻으려면 공격자는 콘텐츠 스크립트에서 익스텐션 코어로 악의적인 입력을 전달하고 익스텐션 코어에서 네이티브 바이너리로 전달해야 합니다. {% endhint %}

익스텐션의 각 구성 요소는 강력한 보호 경계에 의해 서로 분리됩니다. 각 구성 요소는 별도의 운영 체제 프로세스에서 실행됩니다. 콘텐츠 스크립트 및 익스텐션 코어는 대부분의 운영 체제 서비스에 사용할 수 없는 샌드박스 프로세스에서 실행됩니다.

또한 콘텐츠 스크립트는 별도의 JavaScript 힙에서 실행되어 관련 웹 페이지와 분리됩니다. 콘텐츠 스크립트와 웹 페이지는 동일한 기본 DOM에 액세스하지만 두 가지는 JavaScript 포인터를 교환하지 않으므로 JavaScript 기능이 누출되지 않습니다.

manifest.json

Chrome 익스텐션은 .crx 파일 확장자를 가진 ZIP 폴더일 뿐입니다. 익스텐션의 코어는 폴더 루트에 있는 manifest.json 파일로, 레이아웃, 권한 및 기타 구성 옵션을 지정합니다.

예시:

{
"manifest_version": 2,
"name": "My extension",
"version": "1.0",
"permissions": [
"storage"
],
"content_scripts": [
{
"js": [
"script.js"
],
"matches": [
"https://example.com/*",
"https://www.example.com/*"
],
"exclude_matches": ["*://*/*business*"],
}
],
"background": {
"scripts": [
"background.js"
]
},
"options_ui": {
"page": "options.html"
}
}

content_scripts

콘텐츠 스크립트는 사용자가 일치하는 페이지로 탐색할 때마다 로드됩니다. 우리의 경우 https://example.com/* 표현과 일치하고 *://*/*/business* 정규 표현식과 일치하지 않는 모든 페이지에 로드됩니다. 이들은 페이지 자체의 스크립트처럼 실행되며 페이지의 문서 객체 모델(DOM)에 임의로 액세스할 수 있습니다.

"content_scripts": [
{
"js": [
"script.js"
],
"matches": [
"https://example.com/*",
"https://www.example.com/*"
],
"exclude_matches": ["*://*/*business*"],
}
],

include_globs 및 **exclude_globs**를 사용하여 더 많은 URL을 포함하거나 제외하는 것도 가능합니다.

이는 페이지에 설명 버튼을 추가하는 예제 콘텐츠 스크립트이며, 저장소 API를 사용하여 확장 프로그램의 저장소에서 message 값을 검색합니다.

chrome.storage.local.get("message", result =>
{
let div = document.createElement("div");
div.innerHTML = result.message + " <button>Explain</button>";
div.querySelector("button").addEventListener("click", () =>
{
chrome.runtime.sendMessage("explain");
});
document.body.appendChild(div);
});

이 버튼을 클릭할 때 콘텐츠 스크립트에 의해 확장 프로그램 페이지로 메시지가 전송되며, runtime.sendMessage() API를 활용합니다. 이는 콘텐츠 스크립트가 API에 직접 액세스하는 것에 제한이 있기 때문에 발생하며, storage가 소수의 예외 사항 중 하나입니다. 이러한 예외 사항을 넘어서는 기능의 경우, 콘텐츠 스크립트가 통신할 수 있는 확장 프로그램 페이지로 메시지가 전송됩니다.

{% hint style="warning" %} 브라우저에 따라 콘텐츠 스크립트의 기능이 약간 다를 수 있습니다. 크로미움 기반 브라우저의 경우, 기능 목록은 Chrome Developers documentation에서 확인할 수 있으며, 파이어폭스의 경우 MDN이 주요 소스로 작용합니다.
또한 콘텐츠 스크립트는 백그라운드 스크립트와 통신할 수 있는 능력을 갖고 있어서 작업을 수행하고 응답을 전달할 수 있습니다. {% endhint %}

크롬에서 콘텐츠 스크립트를 보고 디버깅하기 위해 크롬 개발자 도구 메뉴에는 옵션 > 더보기 도구 > 개발자 도구를 선택하거나 Ctrl + Shift + I를 누르면 접근할 수 있습니다.

개발자 도구가 표시된 후 소스 탭을 클릭한 다음 콘텐츠 스크립트 탭을 클릭해야 합니다. 이를 통해 여러 확장 프로그램에서 실행 중인 콘텐츠 스크립트를 관찰하고 실행 흐름을 추적하기 위해 중단점을 설정할 수 있습니다.

삽입된 콘텐츠 스크립트

{% hint style="success" %} 콘텐츠 스크립트는 필수적이지 않다는 점을 유의하십시오. 동적으로 스크립트를 삽입하거나 프로그래밍 방식으로 웹 페이지에 **tabs.executeScript**를 통해 삽입하는 것도 가능합니다. 이는 실제로 더 세분화된 제어를 제공합니다. {% endhint %}

콘텐츠 스크립트를 프로그래밍 방식으로 삽입하기 위해서는, 스크립트가 삽입될 페이지에 대한 호스트 권한이 확장 프로그램에 필요합니다. 이러한 권한은 확장 프로그램의 매니페스트 내에서 요청하거나 activeTab을 통해 일시적으로 보안을 설정할 수 있습니다.

activeTab을 기반으로 한 확장 프로그램 예시

{% code title="manifest.json" %}

{
"name": "My extension",
...
"permissions": [
"activeTab",
"scripting"
],
"background": {
"service_worker": "background.js"
},
"action": {
"default_title": "Action Button"
}
}

{% endcode %}

  • 클릭 시 JS 파일 주입:
// content-script.js
document.body.style.backgroundColor = "orange";

//service-worker.js - Inject the JS file
chrome.action.onClicked.addListener((tab) => {
chrome.scripting.executeScript({
target: { tabId: tab.id },
files: ["content-script.js"]
});
});
  • 클릭 시 함수 주입:
//service-worker.js - Inject a function
function injectedFunction() {
document.body.style.backgroundColor = "orange";
}

chrome.action.onClicked.addListener((tab) => {
chrome.scripting.executeScript({
target : {tabId : tab.id},
func : injectedFunction,
});
});

스크립팅 권한 예제

// service-workser.js
chrome.scripting.registerContentScripts([{
id : "test",
matches : [ "https://*.example.com/*" ],
excludeMatches : [ "*://*/*business*" ],
js : [ "contentScript.js" ],
}]);

// Another example
chrome.tabs.executeScript(tabId, { file: "content_script.js" });

내포 또는 제외할 URL을 더 추가하거나 제외하는 것도 가능합니다. include_globs 및 **exclude_globs**를 사용할 수 있습니다.

콘텐츠 스크립트 run_at

run_at 필드는 JavaScript 파일이 웹 페이지에 주입되는 시점을 제어합니다. 선호되는 기본값은 "document_idle"입니다.

가능한 값은 다음과 같습니다:

  • document_idle: 가능한 경우 언제든지
  • document_start: css에서 파일이 로드된 후이지만 다른 DOM이 구성되거나 다른 스크립트가 실행되기 전입니다.
  • document_end: DOM이 완전히 완성된 직후이지만 이미지 및 프레임과 같은 하위 리소스가 로드되기 전입니다.

manifest.json을 통해

{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["https://*.example.com/*"],
"run_at": "document_idle",
"js": ["contentScript.js"]
}
],
...
}

**service-worker.js**를 통해

chrome.scripting.registerContentScripts([{
id : "test",
matches : [ "https://*.example.com/*" ],
runAt : "document_idle",
js : [ "contentScript.js" ],
}]);

백그라운드

콘텐츠 스크립트로 전송된 메시지는 백그라운드 페이지에 의해 수신되며, 확장 프로그램의 구성 요소들 간의 조정에서 중추적인 역할을 합니다. 특히 백그라운드 페이지는 직접적인 사용자 상호 작용 없이 조용히 작동하면서 확장 프로그램의 수명 동안 지속됩니다. 복잡한 상호 작용과 상태 관리를 가능케 하는 자체 Document Object Model (DOM)을 보유하고 있습니다.

주요 포인트:

  • 백그라운드 페이지 역할: 확장 프로그램의 다양한 부분들 간의 통신과 조정을 보장하는 신경 센터 역할을 합니다.
  • 지속성: 사용자에게는 보이지 않지만 확장 프로그램의 기능에 중요한 역할을 합니다.
  • 자동 생성: 명시적으로 정의되지 않은 경우, 브라우저는 자동으로 백그라운드 페이지를 생성합니다. 이 자동 생성된 페이지에는 확장 프로그램 매니페스트에서 지정된 모든 백그라운드 스크립트가 포함되어 있어, 확장 프로그램의 백그라운드 작업이 원활하게 작동합니다.

{% hint style="success" %} 명시적으로 선언되지 않은 경우 브라우저가 백그라운드 페이지를 자동으로 생성하여 필요한 모든 백그라운드 스크립트가 통합되고 작동되어, 확장 프로그램의 설정 프로세스가 간소화됩니다. {% endhint %}

예시 백그라운드 스크립트:

chrome.runtime.onMessage.addListener((request, sender, sendResponse) =>
{
if (request == "explain")
{
chrome.tabs.create({ url: "https://example.net/explanation" });
}
})

이는 runtime.onMessage API를 사용하여 메시지를 수신합니다. "explain" 메시지를 수신하면 tabs API를 사용하여 새 탭에서 페이지를 엽니다.

백그라운드 스크립트를 디버깅하려면 확장 프로그램 세부 정보로 이동하여 서비스 워커를 검사할 수 있습니다. 이렇게 하면 백그라운드 스크립트가 있는 개발자 도구가 열립니다:

옵션 페이지 및 기타

브라우저 확장 프로그램에는 다양한 종류의 페이지가 포함될 수 있습니다:

  • 작업 페이지확장 프로그램 아이콘을 클릭할 때 드롭다운에 표시됩니다.
  • 확장 프로그램이 새 탭에서 로드하는 페이지.
  • 옵션 페이지: 이 페이지는 클릭할 때 확장 프로그램 위에 표시됩니다. 이전 매니페스트에서 나는 chrome://extensions/?options=fadlhnelkbeojnebcbkacjilhnbjfjca에서 이 페이지에 액세스할 수 있었습니다. 또는 다음을 클릭하세요:

이러한 페이지는 백그라운드 페이지처럼 지속적이지 않으며 필요에 따라 동적으로 콘텐츠를 로드합니다. 그럼에도 불구하고 이러한 페이지는 백그라운드 페이지와 유사한 기능을 공유합니다:

  • 콘텐츠 스크립트와의 통신: 백그라운드 페이지와 유사하게, 이러한 페이지는 콘텐츠 스크립트로부터 메시지를 수신하여 확장 프로그램 내에서 상호 작용을 용이하게 합니다.
  • 확장 프로그램별 API 액세스: 이러한 페이지는 확장 프로그램별 API에 대한 포괄적인 액세스 권한을 갖습니다. 확장 프로그램에 정의된 권한에 따라 제한됩니다.

permissionshost_permissions

permissions 및 **host_permissions**은 브라우저 확장 프로그램이 가지는 권한(저장소, 위치 등)어떤 웹 페이지에서 사용할 수 있는지를 나타내는 manifest.json의 항목입니다.

브라우저 확장 프로그램이 매우 특권을 가질 수 있기 때문에, 악의적인 확장 프로그램이나 침해를 당한 확장 프로그램은 공격자가 민감한 정보를 탈취하고 사용자를 감시하는 다양한 수단을 허용할 수 있습니다.

이러한 설정이 어떻게 작동하며 어떻게 남용될 수 있는지 확인하려면 다음을 참조하십시오:

{% content-ref url="browext-permissions-and-host_permissions.md" %} browext-permissions-and-host_permissions.md {% endcontent-ref %}

content_security_policy

content security policymanifest.json 내에서도 선언할 수 있습니다. 정의된 경우 취약할 수 있습니다.

브라우저 확장 프로그램 페이지의 기본 설정은 상당히 제한적입니다:

script-src 'self'; object-src 'self';

CSP 및 가능한 우회 방법에 대한 자세한 정보는 다음을 확인하십시오:

{% content-ref url="../content-security-policy-csp-bypass/" %} content-security-policy-csp-bypass {% endcontent-ref %}

web_accessible_resources

웹페이지가 브라우저 확장 프로그램의 페이지(예: .html 페이지)에 액세스하려면 해당 페이지를 manifest.jsonweb_accessible_resources 필드에 언급해야 합니다.
예시:

{
...
"web_accessible_resources": [
{
"resources": [ "images/*.png" ],
"matches": [ "https://example.com/*" ]
},
{
"resources": [ "fonts/*.woff" ],
"matches": [ "https://example.com/*" ]
}
],
...
}

이러한 페이지는 다음과 같은 URL에서 접근할 수 있습니다:

chrome-extension://<extension-id>/message.html

공개 확장 프로그램에서 확장 프로그램 ID에 액세스할 수 있습니다:

그러나 manifest.json 매개변수 **use_dynamic_url**을 사용하면이 ID가 동적 일 수 있습니다.

{% hint style="success" %} 여기에 페이지가 언급되어 있더라도 콘텐츠 보안 정책 덕분에 ClickJacking에 대비되어 있을 수 있습니다. 따라서 ClickJacking 공격이 가능한지 확인하기 전에도 확인해야합니다. (frame-ancestors 섹션) {% endhint %}

이러한 페이지에 액세스 할 수있게되면 이러한 페이지가 잠재적으로 취약한 ClickJacking이 됩니다:

{% content-ref url="browext-clickjacking.md" %} browext-clickjacking.md {% endcontent-ref %}

{% hint style="success" %} 이러한 페이지가 무작위 URL이 아닌 확장 프로그램에 의해서만로드되도록 허용하면 ClickJacking 공격을 방지 할 수 있습니다. {% endhint %}

{% hint style="danger" %} **web_accessible_resources**에서 페이지 및 확장 프로그램의 다른 페이지도 백그라운드 스크립트에 연락할 수 있습니다. 따라서 이러한 페이지 중 하나가 XSS에 취약하면 더 큰 취약성을 열 수 있습니다.

또한, **web_accessible_resources**에 지정된 페이지는 iframe 내에서만 열 수 있지만, 새 탭에서는 확장 프로그램의 모든 페이지에 액세스 할 수 있습니다. 따라서 동일한 매개 변수를 남용하는 XSS가 발견되면 **web_accessible_resources**에 구성되어 있지 않더라도 남용될 수 있습니다. {% endhint %}

externally_connectable

문서에 따르면, "externally_connectable" 매니페스트 속성은 runtime.connectruntime.sendMessage를 통해 확장 프로그램에 연결할 수있는 어떤 확장 프로그램 및 웹 페이지가 연결할 수 있는지 선언합니다.

  • externally_connectable 키가 확장 프로그램의 매니페스트에 선언되지 않았거나 **"ids": ["*"]**로 선언되어 있으면, 모든 확장 프로그램이 연결할 수 있지만 웹 페이지는 연결할 수 없습니다.
  • 특정 ID가 지정된 경우, "ids": ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"]와 같이, 해당 응용 프로그램만 연결할 수 있습니다.
  • 일치 항목이 지정된 경우 해당 웹 앱이 연결할 수 있습니다:
"matches": [
"https://*.google.com/*",
"*://*.chromium.org/*",
  • 비어 있음으로 지정된 경우: "externally_connectable": {}, 어떤 앱 또는 웹도 연결할 수 없습니다.

여기에 나와 있는 확장 프로그램 및 URL이 적을수록 공격 표면이 작아집니다.

{% hint style="danger" %} 만약 XSS 또는 탈취에 취약한 웹 페이지가 **externally_connectable**에 표시되어 있다면, 공격자는 백그라운드 스크립트에 직접 메시지를 보낼 수 있게 되어 Content Script 및 해당 CSP를 완전히 우회할 수 있습니다.

따라서, 이것은 매우 강력한 우회입니다.

게다가, 클라이언트가 악성 확장 프로그램을 설치하면, 취약한 확장 프로그램과 통신할 수 없더라도, 허용된 웹 페이지에 XSS 데이터를 삽입하거나 WebRequest 또는 DeclarativeNetRequest API를 남용하여 대상 도메인의 요청을 조작하여 JavaScript 파일의 요청을 변경할 수 있습니다. (대상 페이지의 CSP가 이러한 공격을 방지할 수 있음에 유의하십시오). 이 아이디어는 이 설명서에서 나온 것입니다. {% endhint %}

통신 요약

확장 프로그램 <--> 웹앱

콘텐츠 스크립트와 웹 페이지 간에 메시지를 전송하기 위해 일반적으로 메시지가 사용됩니다. 따라서, 웹 애플리케이션에서는 일반적으로 window.postMessage 함수 호출을 찾을 수 있으며, 콘텐츠 스크립트에서는 **window.addEventListener**와 같은 리스너가 있을 것입니다. 그러나, 확장 프로그램은 또한 웹 애플리케이션에 Post Message를 보내 통신할 수도 있습니다 (따라서 웹은 이를 예상해야 함) 또는 웹에 새 스크립트를 로드하도록 할 수도 있습니다.

확장 프로그램 내부

일반적으로 chrome.runtime.sendMessage 함수를 사용하여 확장 프로그램 내에서 메시지를 보내고 (일반적으로 background 스크립트에서 처리됨) 이를 수신하고 처리하기 위해 리스너를 선언하여 **chrome.runtime.onMessage.addListener**를 호출합니다.

또한 **chrome.runtime.connect()**를 사용하여 단일 메시지를 보내는 대신 지속적인 연결을 갖도록 할 수도 있으며, 다음 예제와 같이 메시지를 보내고 받을 수 있습니다:

chrome.runtime.connect() 예제 ```javascript var port = chrome.runtime.connect();

// Listen for messages from the web page window.addEventListener("message", (event) => { // Only accept messages from the same window if (event.source !== window) { return; }

// Check if the message type is "FROM_PAGE" if (event.data.type && (event.data.type === "FROM_PAGE")) { console.log("Content script received: " + event.data.text); // Forward the message to the background script port.postMessage({ type: 'FROM_PAGE', text: event.data.text }); } }, false);

// Listen for messages from the background script port.onMessage.addListener(function(msg) { console.log("Content script received message from background script:", msg); // Handle the response message from the background script });

</details>

백그라운드 스크립트에서 특정 탭에 위치한 콘텐츠 스크립트로 메시지를 보내는 것도 가능합니다. 이를 위해 **`chrome.tabs.sendMessage`**을 호출하여 메시지를 보낼 **탭의 ID**를 지정해야 합니다.

### 허용된 `externally_connectable`에서 확장 프로그램으로

`externally_connectable` 구성에서 허용된 **웹 앱 및 외부 브라우저 확장 프로그램**은 다음을 사용하여 요청을 보낼 수 있습니다:
```javascript
chrome.runtime.sendMessage(extensionId, ...

확장 프로그램 ID를 언급해야 하는 경우가 있습니다.

웹 ↔︎ 콘텐츠 스크립트 통신

콘텐츠 스크립트가 작동하는 환경과 호스트 페이지가 존재하는 환경은 서로 분리되어 있어 격리가 보장됩니다. 이 격리 상태에도 불구하고 두 환경은 페이지의 **문서 객체 모델 (DOM)**과 상호 작용할 수 있는 능력을 갖고 있습니다. 호스트 페이지가 콘텐츠 스크립트와 통신하거나 간접적으로 콘텐츠 스크립트를 통해 확장 프로그램과 통신하기 위해서는 양쪽이 접근 가능한 DOM을 통신 채널로 활용해야 합니다.

메시지 게시

{% code title="content-script.js" %}

// This is like "chrome.runtime.sendMessage" but to maintain the connection
var port = chrome.runtime.connect();

window.addEventListener("message", (event) => {
// We only accept messages from ourselves
if (event.source !== window) {
return;
}

if (event.data.type && (event.data.type === "FROM_PAGE")) {
console.log("Content script received: " + event.data.text);
// Forward the message to the background script
port.postMessage(event.data.text);
}
}, false);

{% endcode %}

{% code title="example.js" %}

document.getElementById("theButton").addEventListener("click", () => {
window.postMessage(
{type : "FROM_PAGE", text : "Hello from the webpage!"}, "*");
}, false);

{% endcode %}

안전한 포스트 메시지 통신은 받은 메시지의 신뢰성을 확인해야 합니다. 이는 다음을 확인하여 수행할 수 있습니다:

  • event.isTrusted: 이 값은 사용자 조작으로 이벤트가 트리거된 경우에만 True입니다.
  • 콘텐츠 스크립트는 사용자가 일부 조치를 취한 경우에만 메시지를 기대할 수 있습니다.
  • 원본 도메인: 메시지를 기대하는 경우에는 허용 목록에 있는 도메인만 허용할 수 있습니다.
  • 정규식을 사용하는 경우 매우 주의해야 합니다.
  • 소스: received_message.source !== window를 사용하여 메시지가 콘텐츠 스크립트가 수신 대기 중인 동일한 창에서 온지 확인할 수 있습니다.

이전 체크는 수행되었더라도 취약할 수 있으므로 다음 페이지에서 잠재적인 포스트 메시지 우회를 확인하세요:

{% content-ref url="../postmessage-vulnerabilities/" %} postmessage-vulnerabilities {% endcontent-ref %}

Iframe

또 다른 통신 방법은 Iframe URL을 통해 가능할 수 있습니다. 예제는 다음에서 찾을 수 있습니다:

{% content-ref url="browext-xss-example.md" %} browext-xss-example.md {% endcontent-ref %}

DOM

이것은 "정확히" 통신 방법은 아니지만, 웹과 콘텐츠 스크립트는 웹 DOM에 액세스할 수 있습니다. 따라서, 콘텐츠 스크립트가 그것에서 정보를 읽고 웹 DOM을 신뢰한다면, 웹은 이 데이터를 수정할 수 있습니다(웹은 신뢰해서는 안 되거나 XSS 취약점이 있기 때문에) 그리고 콘텐츠 스크립트를 compromise할 수 있습니다.

또한 브라우저 확장 프로그램을 compromise하기 위한 DOM 기반 XSS 예제를 다음에서 찾을 수 있습니다:

{% content-ref url="browext-xss-example.md" %} browext-xss-example.md {% endcontent-ref %}

콘텐츠 스크립트 ↔︎ 백그라운드 스크립트 통신

콘텐츠 스크립트는 runtime.sendMessage() 또는 tabs.sendMessage() 함수를 사용하여 일회성 JSON-직렬화 가능한 메시지를 보낼 수 있습니다.

응답을 처리하려면 반환된 Promise를 사용하십시오. 그러나 하위 호환성을 위해 마지막 인수로 콜백을 전달할 수도 있습니다.

콘텐츠 스크립트에서 요청을 보내는 방법은 다음과 같습니다:

(async () => {
const response = await chrome.runtime.sendMessage({greeting: "hello"});
// do something with response here, not outside the function
console.log(response);
})();

확장 프로그램에서 요청을 보내기 (보통 백그라운드 스크립트). 선택된 탭의 콘텐츠 스크립트에 메시지를 보내는 방법의 예시:

// From https://stackoverflow.com/questions/36153999/how-to-send-a-message-between-chrome-extension-popup-and-content-script
(async () => {
const [tab] = await chrome.tabs.query({active: true, lastFocusedWindow: true});
const response = await chrome.tabs.sendMessage(tab.id, {greeting: "hello"});
// do something with response here, not outside the function
console.log(response);
})();

수신 측에서는 메시지를 처리하기 위해 runtime.onMessage 이벤트 리스너를 설정해야 합니다. 이는 콘텐츠 스크립트나 확장 프로그램 페이지에서 동일하게 보입니다.

// From https://stackoverflow.com/questions/70406787/javascript-send-message-from-content-js-to-background-js
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
console.log(sender.tab ?
"from a content script:" + sender.tab.url :
"from the extension");
if (request.greeting === "hello")
sendResponse({farewell: "goodbye"});
}
);

예를 들어, 강조된 예제에서 **sendResponse()**가 동기적으로 실행되었습니다. sendResponse()를 비동기적으로 실행하기 위해 onMessage 이벤트 핸들러를 수정하려면 return true;를 반드시 포함해야 합니다.

중요한 고려 사항은 여러 페이지가 onMessage 이벤트를 수신하도록 설정된 시나리오에서 특정 이벤트에 대해 sendResponse()를 실행하는 첫 번째 페이지만이 응답을 효과적으로 전달할 수 있다는 것입니다. 동일한 이벤트에 대한 이후 응답은 고려되지 않습니다.

새로운 확장 프로그램을 작성할 때는 콜백 대신 프로미스를 선호해야 합니다. 콜백의 사용에 관한 중요한 점은 sendResponse() 함수가 동기적인 컨텍스트 내에서 직접 실행되거나 이벤트 핸들러가 비동기 작업을 나타내기 위해 true를 반환하는 경우에만 유효하다는 것입니다. 핸들러 중 하나도 true를 반환하지 않거나 sendResponse() 함수가 메모리에서 제거되면 (가비지 수집), sendMessage() 함수와 관련된 콜백이 기본적으로 트리거됩니다.

메모리/코드/클립보드에 민감한 정보

브라우저 확장 프로그램이 민감한 정보를 메모리에 저장하는 경우, 이 정보가 덤프될 수 있으며 (특히 Windows 기기에서) 해당 정보를 검색할 수 있습니다.

따라서, 브라우저 확장 프로그램의 메모리는 안전하다고 보기 어렵고 자격 증명이나 니모닉 구절과 같은 민감한 정보를 저장해서는 안됩니다.

물론, 코드에 민감한 정보를 넣지 않아야 하며, 그렇게 하면 공개될 것입니다.

브라우저에서 메모리를 덤프하려면 프로세스 메모리를 덤프하거나 브라우저 확장 프로그램의 설정으로 이동하여 **Inspect pop-up**을 클릭 -> Memory 섹션에서 **Take a snaphost**를 클릭하고 스냅샷 내에서 민감한 정보를 검색하기 위해 **CTRL+F**를 사용할 수 있습니다.

또한, 니모닉 키나 비밀번호와 같이 매우 민감한 정보는 클립보드에 복사되지 않도록 허용해서는 안되며 (또는 클립보드에서 몇 초 후에 제거해야 합니다) 그렇지 않으면 클립보드를 모니터링하는 프로세스가 해당 정보를 얻을 수 있습니다.

브라우저에 확장 프로그램 로드하기

  1. 브라우저 확장 프로그램을 다운로드하고 압축 해제합니다.
  2. **chrome://extensions/**로 이동하고 개발자 모드활성화합니다.
  3. 압축 해제된 확장 프로그램 로드 버튼을 클릭합니다.

Firefox에서는 **about:debugging#/runtime/this-firefox**로 이동하고 임시 애드온 로드 버튼을 클릭합니다.

스토어에서 소스 코드 가져오기

크롬 확장 프로그램의 소스 코드는 다양한 방법으로 얻을 수 있습니다. 각 옵션에 대한 자세한 설명과 지침은 아래에 제공됩니다.

명령줄을 통한 ZIP 파일로 확장 프로그램 다운로드

크롬 확장 프로그램의 소스 코드는 명령줄을 사용하여 ZIP 파일로 다운로드할 수 있습니다. 이를 위해 curl을 사용하여 특정 URL에서 ZIP 파일을 가져와서 ZIP 파일의 내용을 디렉토리로 추출해야 합니다. 다음 단계를 따릅니다:

  1. "extension_id"를 확장 프로그램의 실제 ID로 대체합니다.
  2. 다음 명령을 실행합니다:
extension_id=your_extension_id   # Replace with the actual extension ID
curl -L -o "$extension_id.zip" "https://clients2.google.com/service/update2/crx?response=redirect&os=mac&arch=x86-64&nacl_arch=x86-64&prod=chromecrx&prodchannel=stable&prodversion=44.0.2403.130&x=id%3D$extension_id%26uc"
unzip -d "$extension_id-source" "$extension_id.zip"

CRX Viewer 웹사이트 사용

https://robwu.nl/crxviewer/

CRX Viewer 확장 프로그램 사용

또 다른 편리한 방법은 오픈 소스 프로젝트인 Chrome Extension Source Viewer를 사용하는 것입니다. Chrome Web Store에서 설치할 수 있습니다. 뷰어의 소스 코드는 GitHub 저장소에서 사용할 수 있습니다.

로컬로 설치된 확장 프로그램의 소스 보기

로컬로 설치된 Chrome 확장 프로그램도 검사할 수 있습니다. 다음과 같이 진행할 수 있습니다:

  1. "Profile Path" 필드를 찾아 chrome://version/를 방문하여 Chrome 로컬 프로필 디렉토리에 액세스합니다.
  2. 프로필 디렉토리 내의 Extensions/ 하위 폴더로 이동합니다.
  3. 이 폴더에는 일반적으로 읽기 가능한 형식으로 소스 코드가 포함된 모든 설치된 확장 프로그램이 포함되어 있습니다.

확장 프로그램을 식별하기 위해 ID를 이름에 매핑할 수 있습니다:

  • about:extensions 페이지에서 개발자 모드를 활성화하여 각 확장 프로그램의 ID를 볼 수 있습니다.
  • 각 확장 프로그램의 폴더 내에는 읽기 가능한 name 필드가 포함된 manifest.json 파일이 있어 확장 프로그램을 식별하는 데 도움이 됩니다.

파일 아카이버 또는 언패커 사용

Chrome Web Store로 이동하여 확장 프로그램을 다운로드합니다. 파일의 확장자는 .crx일 것입니다. 파일 확장자를 .zip으로 변경합니다. WinRAR, 7-Zip 등의 파일 아카이버를 사용하여 ZIP 파일의 내용을 추출합니다.

Chrome의 개발자 모드 사용

Chrome을 열고 chrome://extensions/로 이동합니다. 오른쪽 상단에서 "개발자 모드"를 활성화합니다. "압축 해제된 확장 프로그램을 로드합니다..."를 클릭합니다. 확장 프로그램이 있는 디렉토리로 이동합니다. 이는 소스 코드를 다운로드하지는 않지만 이미 다운로드하거나 개발된 확장 프로그램의 코드를 보는 데 유용합니다.

보안 감사 체크리스트

브라우저 확장 프로그램은 제한된 공격 표면을 가지고 있지만 일부는 취약점이나 잠재적인 강화 개선 사항을 포함할 수 있습니다. 다음은 가장 일반적인 것들입니다:

  • 요청된 **permissions**을 최대한 제한합니다.
  • **host_permissions**을 최대한 제한합니다.
  • **content_security_policy**를 강력하게 사용합니다.
  • **externally_connectable**을 가능한 한 제한하고 필요 없는 경우 기본값으로 남기지 않고 **{}**를 명시합니다.
  • 여기서 XSS나 탈취 가능한 URL이 언급된 경우, 공격자가 백그라운드 스크립트로 직접 메시지를 보낼 수 있습니다. 매우 강력한 우회입니다.
  • **web_accessible_resources**를 가능한 한 제한하고 가능하면 비어 있게 합니다.
  • **web_accessible_resources**가 없지 않은 경우 ClickJacking을 확인합니다.
  • 확장 프로그램에서 웹 페이지통신이 발생하는 경우, 통신으로 인한 XSS 취약점을 확인합니다.
  • Post Messages를 사용하는 경우 Post Message 취약점을 확인합니다.
  • 콘텐츠 스크립트가 DOM 세부 정보에 액세스하는 경우, 해당 정보가 웹에서 수정되어 XSS를 도입하지 않는지 확인합니다.
  • 특히 이 통신이 콘텐츠 스크립트 -> 백그라운드 스크립트 통신에 관여하는 경우 특별히 강조합니다.
  • 브라우저 확장 프로그램 코드 내에 민감한 정보를 저장해서는 안 됩니다.
  • 브라우저 확장 프로그램 메모리에 민감한 정보를 저장해서는 안 됩니다.

도구

Tarnish

  • 제공된 Chrome 웹스토어 링크에서 Chrome 확장 프로그램을 추출합니다.
  • manifest.json 뷰어: 확장 프로그램의 manifest를 JSON 형식으로 표시합니다.
  • 지문 분석: web_accessible_resources의 감지 및 Chrome 확장 프로그램 지문 JavaScript의 자동 생성.
  • 잠재적인 Clickjacking 분석: web_accessible_resources 지시문이 설정된 확장 프로그램 HTML 페이지의 감지. 페이지의 목적에 따라 클릭재킹에 취약할 수 있습니다.
  • 권한 경고 뷰어: 사용자가 확장 프로그램을 설치하려고 할 때 표시되는 모든 Chrome 권한 프롬프트 경고 목록을 표시합니다.
  • 위험한 기능: 공격자가 악용할 수 있는 위험한 기능의 위치를 표시합니다 (예: innerHTML, chrome.tabs.executeScript와 같은 기능).
  • 진입점: 사용자/외부 입력을 받는 확장 프로그램의 위치를 표시합니다. 이는 확장 프로그램의 표면적인 영역을 이해하고 확장 프로그램에 악의적으로 조작된 데이터를 보낼 수 있는 잠재적인 지점을 찾는 데 유용합니다.
  • 위험한 기능 및 진입점 스캐너는 다음을 생성된 경고에 대해 제공합니다:
  • 경고를 일으킨 코드 스니펫 및 라인.
  • 문제에 대한 설명.
  • 코드를 포함한 전체 소스 파일을 볼 수 있는 "파일 보기" 버튼.
  • 경고를 일으킨 파일의 경로.
  • 경고를 일으킨 파일의 전체 Chrome 확장 프로그램 URI.
  • JavaScript 파일의 취약한 라인이 포함된 경우, 해당 라인이 포함된 모든 페이지의 경로 및 해당 페이지의 유형 및 web_accessible_resource 상태.
  • 콘텐츠 보안 정책 (CSP) 분석 및 우회 확인기: 확장 프로그램의 CSP의 취약점을 지적하고 허용된 CDNs 등으로 인해 CSP를 우회할 수 있는 잠재적인 방법을 밝힙니다.
  • 알려진 취약한 라이브러리: Retire.js를 사용하여 알려진 취약한 JavaScript 라이브러리 사용을 확인합니다.
  • 확장 프로그램 및 형식화된 버전 다운로드.
  • 원본 확장 프로그램 다운로드.
  • 확장 프로그램의 형식화된 버전 다운로드 (자동으로 예쁘게 정리된 HTML 및 JavaScript).
  • 스캔 결과의 자동 캐싱, 확장 프로그램 스캔 실행은 처음에는 많은 시간이 걸리지만 두 번째로 실행할 때는 결과가 캐시되어 거의 즉시 실행됩니다.
  • 링크 가능한 보고서 URL, tarnish에 의해 생성된 확장 프로그램 보고서를 다른 사람에게 쉽게 링크할 수 있습니다.

Neto

프로젝트 Neto는 Firefox 및 Chrome과 같은 잘 알려진 브라우저용 브라우저 플러그인 및 확장 프로그램의 숨겨진 기능을 분석하고 해독하기 위해 고안된 Python 3 패키지입니다. 이는 패키지된 파일을 압축 해제하여 확장 프로그램의 manifest.json, 로컬라이제이션 폴더 또는 Javascript 및 HTML 소스 파일에서 이러한 기능을 추출하는 프로세스를 자동화합니다.

참고 자료

htARTE (HackTricks AWS Red Team Expert)를 통해 제로부터 AWS 해킹을 전문가로 배우세요

HackTricks를 지원하는 다른 방법: