ãã©ãŠã¶æ¡åŒµæ©èœ Pentesting Methodology
Tip
AWSãããã³ã°ãåŠã³ãå®è·µããïŒ
HackTricks Training AWS Red Team Expert (ARTE)
GCPãããã³ã°ãåŠã³ãå®è·µããïŒHackTricks Training GCP Red Team Expert (GRTE)
Azureãããã³ã°ãåŠã³ãå®è·µããïŒ
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricksããµããŒããã
- ãµãã¹ã¯ãªãã·ã§ã³ãã©ã³ã確èªããŠãã ããïŒ
- **ð¬ Discordã°ã«ãŒããŸãã¯ãã¬ã°ã©ã ã°ã«ãŒãã«åå ããããTwitter ðŠ @hacktricks_liveããã©ããŒããŠãã ããã
- HackTricksããã³HackTricks Cloudã®GitHubãªããžããªã«PRãæåºããŠãããã³ã°ããªãã¯ãå ±æããŠãã ããã
åºæ¬æ å ±
ãã©ãŠã¶æ¡åŒµã¯ JavaScript ã§æžããããã©ãŠã¶ã«ãã£ãŠããã¯ã°ã©ãŠã³ãã§èªã¿èŸŒãŸããŸããããã¯ç¬èªã® DOM ãæã¡ãä»ãµã€ãã® DOM ãšçžäºäœçšã§ããŸããããã¯ä»ãµã€ãã®æ©å¯æ§ãå®å šæ§ãå¯çšæ§ (CIA) ã䟵害ããå¯èœæ§ãããããšãæå³ããŸãã
äž»ãªã³ã³ããŒãã³ã
æ¡åŒµæ©èœã®æ§æã¯èŠèŠåãããšåãããããã3ã€ã®ã³ã³ããŒãã³ãã§æ§æãããŸããããããã詳ããèŠãŠãããŸãããã
 (1) (1).png)
Content Scripts
å content script 㯠åäžã®ãŠã§ãããŒãž ã® DOM ã«çŽæ¥ã¢ã¯ã»ã¹ã§ãããã®ãã æœåšçã«æªæã®ããå ¥å ã«ãããããŸãããã ããcontent script ãæã€æš©é㯠extension core ã«ã¡ãã»ãŒãžãéãèœå以å€ã«ãããŸããã
Extension Core
extension core ã¯æ¡åŒµæ©èœã®ã»ãšãã©ã®æš©éïŒã¢ã¯ã»ã¹ãå«ã¿ãŸãããextension core ã web ã³ã³ãã³ããšããåãã§ããã®ã¯ XMLHttpRequest ãš content scripts ãä»ããå Žåã®ã¿ã§ãããŸããextension core ã¯ãã¹ããã·ã³ãžçŽæ¥ã¢ã¯ã»ã¹ã§ããŸããã
Native Binary
æ¡åŒµæ©èœã¯ ãŠãŒã¶ãŒã®å®å šãªæš©éã§ãã¹ããã·ã³ã«ã¢ã¯ã»ã¹ãã ãã€ãã£ããã€ããªãèš±å¯ããå ŽåããããŸãããã€ãã£ããã€ããªã¯ Flash ãªã©ã®ãã©ãŠã¶ãã©ã°ã€ã³ã§äœ¿ãããæšæºç㪠Netscape Plugin Application Programming Interface (NPAPI) ãéã㊠extension core ãšããåãããŸãã
Boundaries
Caution
ãŠãŒã¶ãŒã®å®å šãªæš©éãåŸãããã«ãæ»æè 㯠extension ã« content script ãã extension ã® core ãžããã㊠extension ã® core ãã native binary ãžæªæã®ããå ¥åãæž¡ãããä»åããå¿ èŠããããŸãã
æ¡åŒµæ©èœã®åã³ã³ããŒãã³ãã¯äºã㫠匷åºãªä¿è·å¢ç ã§åé¢ãããŠããŸããåã³ã³ããŒãã³ã㯠å¥ã ã®ãªãã¬ãŒãã£ã³ã°ã·ã¹ãã ããã»ã¹ ãšããŠå®è¡ãããŸããContent scripts ãš extension cores ã¯ãã»ãšãã©ã® OS ãµãŒãã¹ããã¢ã¯ã»ã¹ã§ããªã ãµã³ãããã¯ã¹ããã»ã¹ ã§å®è¡ãããŸãã
ããã«ãcontent scripts ã¯é¢é£ãããŠã§ãããŒãžãš å¥ã® JavaScript ããŒãã§å®è¡ããã ããšã§åé¢ãããŠããŸããcontent script ãšãŠã§ãããŒãžã¯ åãåºç€ãšãªã DOM ã«ã¢ã¯ã»ã¹ ã§ããŸãããäž¡è 㯠決ã㊠JavaScript ãã€ã³ã¿ã亀æããŸãããããã«ãã JavaScript æ©èœã® leaking ãé²ããŸãã
manifest.json
A Chrome extension 㯠.crx file extension ãæã€ 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* ã®æ£èŠè¡šçŸã«ã¯äžèŽããªãä»»æã®ããŒãžã該åœããŸãããããã¯ããŒãžèªèº«ã®ã¹ã¯ãªããã®ããã«å®è¡ãããããŒãžã® Document Object Model (DOM) ã«ä»»æã«ã¢ã¯ã»ã¹ã§ããŸãã
"content_scripts": [
{
"js": [
"script.js"
],
"matches": [
"https://example.com/*",
"https://www.example.com/*"
],
"exclude_matches": ["*://*/*business*"],
}
],
ããå€ãã® URL ãå«ãããé€å€ãããããã«ã¯ãinclude_globs ãš exclude_globs ã䜿çšããããšãå¯èœã§ãã
以äžã¯ãthe storage API ã䜿çšããŠæ¡åŒµæ©èœã®ã¹ãã¬ãŒãžãã message å€ãååŸãããšãã«ãããŒãžã« explain ãã¿ã³ã远å ããäŸã® content script ã§ãã
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)
})
.png)
ãã®ãã¿ã³ãã¯ãªãã¯ããããšãã³ã³ãã³ãã¹ã¯ãªããã¯runtime.sendMessage() APIãå©çšããŠæ¡åŒµæ©èœããŒãžã«ã¡ãã»ãŒãžãéä¿¡ããŸããããã¯ãã³ã³ãã³ãã¹ã¯ãªãããçŽæ¥ã¢ã¯ã»ã¹ã§ããAPIã«å¶éããããstorage ãæ°å°ãªãäŸå€ã®äžã€ã§ããããã§ãããããã®äŸå€ãè¶
ããæ©èœã«ã€ããŠã¯ãã³ã³ãã³ãã¹ã¯ãªãããããåãã§ããæ¡åŒµæ©èœããŒãžãžã¡ãã»ãŒãžãéãããŸãã
Warning
ãã©ãŠã¶ã«ãã£ãŠã¯ãã³ã³ãã³ãã¹ã¯ãªããã®æ©èœãè¥å¹²ç°ãªãããšããããŸããChromium-based browsers ã®æ©èœäžèЧã¯Chrome Developers documentationã«ãFirefoxã«ã€ããŠã¯äž»èŠãªæ å ±æºãšããŠMDNãåç §ã§ããŸãã
ãŸããã³ã³ãã³ãã¹ã¯ãªããã¯ããã¯ã°ã©ãŠã³ãã¹ã¯ãªãããšéä¿¡ã§ããåäœãå®è¡ãããå¿çãåãåã£ããã§ããç¹ã«ã泚æããŠãã ããã
Chromeã§ã³ã³ãã³ãã¹ã¯ãªããã衚瀺ã»ãããã°ããã«ã¯ãChrome developer tools ã¡ãã¥ãŒã Options > More tools > Developer tools ããéãããCtrl + Shift + I ãæŒããŸãã
ããããããŒããŒã«ã衚瀺ãããããSource tabãã¯ãªãã¯ããç¶ããŠContent Scriptsã¿ããéžæããŸããããã«ãããæ§ã ãªæ¡åŒµæ©èœã§å®è¡äžã®ã³ã³ãã³ãã¹ã¯ãªããã確èªãããã¬ãŒã¯ãã€ã³ããèšå®ããŠå®è¡ãããŒã远跡ã§ããŸãã
Injected content scripts
Tip
Content Scripts ã¯å¿ é ã§ã¯ãããŸãããã¹ã¯ãªãããåçã«æ³šå ¥ãããã
tabs.executeScriptãéããŠããã°ã©ã çã«ããŒãžãžæ³šå ¥ããããšãå¯èœã§ããããã«ããããã现ããªå¶åŸ¡ãå¯èœã«ãªããŸãã
ã³ã³ãã³ãã¹ã¯ãªãããããã°ã©ã çã«æ³šå ¥ããã«ã¯ãæ¡åŒµæ©èœãã¹ã¯ãªãããæ³šå ¥ããããŒãžã«å¯Ÿãã host permissions ãæã£ãŠããå¿ èŠããããŸãããããã®æš©éã¯ãæ¡åŒµã®ãããã§ã¹ãå ã§èŠæ±ããããactiveTab ãçµç±ããŠäžæçã«ååŸã§ããŸãã
activeTab ã䜿ã£ãæ¡åŒµæ©èœã®äŸ
{
"name": "My extension",
...
"permissions": [
"activeTab",
"scripting"
],
"background": {
"service_worker": "background.js"
},
"action": {
"default_title": "Action Button"
}
}
- ã¯ãªãã¯æã«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"],
})
})
- Inject a functionïŒã¯ãªãã¯æïŒ:
//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"],
},
])
background
ã³ã³ãã³ãã¹ã¯ãªããããéä¿¡ãããã¡ãã»ãŒãžã¯ããã¯ã°ã©ãŠã³ãããŒãžã§åä¿¡ãããæ¡åŒµæ©èœã®ã³ã³ããŒãã³ãéã®èª¿æŽã«ãããŠäžå¿çãªåœ¹å²ãæãããŸããç¹ã«ãããã¯ã°ã©ãŠã³ãããŒãžã¯æ¡åŒµæ©èœã®ã©ã€ãã¿ã€ã å šäœã§æç¶ããçŽæ¥ãŠãŒã¶ãŒãšããåãããããšãªãéãã«åäœããŸããç¬èªã® Document Object ModelïŒDOMïŒãæã£ãŠãããè€éãªçžäºäœçšãç¶æ 管çãå¯èœã«ããŸãã
äž»ãªãã€ã³ã:
- ããã¯ã°ã©ãŠã³ãããŒãžã®åœ¹å²: æ¡åŒµæ©èœã®äžæ¢ãšããŠæ©èœããæ¡åŒµæ©èœã®åéšåéã®éä¿¡ãšèª¿æŽã確å®ã«ããŸãã
- æ°žç¶æ§: ãŠãŒã¶ãŒã«ã¯èŠããªãåžžåšããååšã§ãããæ¡åŒµæ©èœã®æ©èœã«äžå¯æ¬ ã§ãã
- èªåçæ: æç€ºçã«å®çŸ©ãããŠããªãå Žåããã©ãŠã¶ã¯ããã¯ã°ã©ãŠã³ãããŒãžãèªåçã«äœæããŸãããã®èªåçæãããããŒãžã«ã¯ãæ¡åŒµæ©èœã®manifestã§æå®ããããã¹ãŠã®ããã¯ã°ã©ãŠã³ãã¹ã¯ãªãããå«ãŸããæ¡åŒµæ©èœã®ããã¯ã°ã©ãŠã³ãã¿ã¹ã¯ãã·ãŒã ã¬ã¹ã«åäœããããšãä¿èšŒããŸãã
Tip
ãã©ãŠã¶ãããã¯ã°ã©ãŠã³ãããŒãžãïŒæç€ºçã«å®£èšãããŠããªãå Žåã«ïŒèªåçæããŠããã䟿å©ãã«ãããå¿ èŠãªãã¹ãŠã®ããã¯ã°ã©ãŠã³ãã¹ã¯ãªãããçµ±åãããŠåäœããæ¡åŒµæ©èœã®ã»ããã¢ãããç°¡çŽ åãããŸãã
ããã¯ã°ã©ãŠã³ãã¹ã¯ãªããã®äŸ:
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request == "explain") {
chrome.tabs.create({ url: "https://example.net/explanation" })
}
})
It uses runtime.onMessage API to listen to messages. When an "explain" message is received, it uses tabs API to open a page in a new tab.
To debug the background script you could go to the extension details and inspect the service worker, this will open the developer tools with the background script:
Options pages and other
Browser extensions can contain various kinds of pages:
- Action pages are displayed in a drop-down when the extension icon is clicked.
- Pages that the extension will load in a new tab.
- Option Pages: This page displays on top of the extension when clicked. In the previous manifest In my case I was able to access this page in
chrome://extensions/?options=fadlhnelkbeojnebcbkacjilhnbjfjcaor clicking:
.png)
Note that these pages arenât persistent like background pages as they load dynamically content on necessity. Despite this, they share certain capabilities with the background page:
- Communication with Content Scripts: Similar to the background page, these pages can receive messages from content scripts, facilitating interaction within the extension.
- Access to Extension-Specific APIs: These pages enjoy comprehensive access to extension-specific APIs, subject to the permissions defined for the extension.
permissions & host_permissions
permissions and host_permissions are entries from the manifest.json that will indicate which permissions the browser extensions has (storage, locationâŠ) and in which web pages.
As browser extensions can be so privileged, a malicious one or one being compromised could allow the attacker different means to steal sensitive information and spy on the user.
Check how these settings work and how they could get abused in:
BrowExt - permissions & host_permissions
content_security_policy
A content security policy can be declared also inside the manifest.json. If there is one defined, it could be vulnerable.
The default setting for browser extension pages is rather restrictive:
script-src 'self'; object-src 'self';
CSP ãš potential bypasses ã®è©³çްã«ã€ããŠã¯æ¬¡ãåç §ããŠãã ãã:
Content Security Policy (CSP) Bypass
web_accessible_resources
ãŠã§ãããŒãžã Browser Extension ã®ããŒãžïŒäŸãã° .html ããŒãžïŒã«ã¢ã¯ã»ã¹ããã«ã¯ããã®ããŒãžã manifest.json ã® web_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
å ¬éãããæ¡åŒµæ©èœã§ã¯ãextension-idã«ã¢ã¯ã»ã¹ã§ããŸã:
.png)
ãã ããmanifest.json ã®ãã©ã¡ãŒã¿ use_dynamic_url ã䜿çšãããŠããå Žåããã® idã¯åçã«ãªãå¯èœæ§ããããŸãã
Tip
ããã§ããŒãžãåæãããŠããŠããContent Security Policy ã«ãã£ãŠ ClickJackingããä¿è·ãããŠããå Žåãããããšã«æ³šæããŠãã ããããããã£ãŠãClickJackingæ»æãå¯èœãã©ããã確å®ããåã«ïŒframe-ancestors ã»ã¯ã·ã§ã³ãå«ããŠïŒç¢ºèªããå¿ èŠããããŸãã
ãããã®ããŒãžã«ã¢ã¯ã»ã¹ã§ããããšã¯ããããã®ããŒãžãæœåšçã«ClickJackingã«è匱ã§ããããšãæå³ããŸã:
Tip
ãããã®ããŒãžãã©ã³ãã 㪠URL ããã§ã¯ãªãæ¡åŒµæ©èœããã®ã¿èªã¿èŸŒããããã«ãããšãClickJacking æ»æãé²ããå¯èœæ§ããããŸãã
Caution
æ¡åŒµæ©èœã®
web_accessible_resourcesã«ããããŒãžããã®ä»ã®ããŒãžã¯ãcontacting background scriptsïŒbackground scripts ã«æ¥è§ŠããïŒ ããšãã§ããç¹ã«æ³šæããŠãã ããããããã£ãŠããããã®ããŒãžã®ããããã XSS ã«è匱ã§ããã°ããã倧ããªè匱æ§ãæãå¯èœæ§ããããŸããããã«ã
web_accessible_resourcesã«ç€ºãããããŒãžã®ã¿ã iframe å ã§éããããšã«æ³šæããŠãã ãããããããæ°ããã¿ãããã¯æ¡åŒµæ©èœ ID ãåããã°æ¡åŒµæ©èœå ã®ä»»æã®ããŒãžãžã¢ã¯ã»ã¹ããããšãå¯èœã§ãããããã£ãŠãåããã©ã¡ãŒã¿ãæªçšãã XSS ãèŠã€ãã£ãå Žåããã®ããŒãžãweb_accessible_resourcesã«èšå®ãããŠããªããŠãæªçšããåŸãŸãã
externally_connectable
ããã¥ã¡ã³ãïŒdocsïŒã«ãããšãmanifest ãããã㣠"externally_connectable" 㯠runtime.connect ããã³ runtime.sendMessage ãä»ããŠãã©ã®æ¡åŒµæ©èœããŠã§ãããŒãžãæ¥ç¶ã§ããã ã宣èšããŸãã
- æ¡åŒµæ©èœã® manifest ã«
externally_connectableããŒã 宣èšãããŠããªã ãã"ids": ["*"]ã®ããã«å®£èšãããŠããå Žåããã¹ãŠã®æ¡åŒµæ©èœãæ¥ç¶ã§ãããããŠã§ãããŒãžã¯æ¥ç¶ã§ããªãã - ç¹å®ã® ID ãæå®ãããŠããå ŽåïŒäŸ:
"ids": ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"]ïŒããããã®ã¢ããªã±ãŒã·ã§ã³ã®ã¿ãæ¥ç¶ã§ããŸãã - matches ãæå®ãããŠããå Žåããããã®ãŠã§ãã¢ããªãæ¥ç¶ã§ããããã«ãªããŸãïŒ
"matches": [
"https://*.google.com/*",
"*://*.chromium.org/*",
- If itâs specified as empty:
"externally_connectable": {}, no app or web will be able to connect.
ããã«æå®ãããæ¡åŒµæ©èœãURLãå°ãªããã°å°ãªãã»ã©ãæ»æå¯Ÿè±¡é¢ã¯å°ãããªããŸãã
Caution
If a web page vulnerable to XSS or takeover is indicated in
externally_connectable, an attacker will be able to send messages directly to the background script, completely bypassing the Content Script and its CSP.Therefore, this is a very powerful bypass.
Moreover, if the client installs a rouge extension, even if it isnât allowed to communicate with the vulnerable extension, it could inject XSS data in an allowed web page or abuse
WebRequestorDeclarativeNetRequestAPIs to manipulate requests on a targeted domain altering a pageâs request for a JavaScript file. (Note that CSP on the targeted page could prevent these attacks). This idea comes from this writeup.
éä¿¡ã®æŠèŠ
Extension <â> WebApp
content script ãš web ããŒãžéã®éä¿¡ã«ã¯éåžž post messages ã䜿ãããŸãããããã£ãŠãweb ã¢ããªã±ãŒã·ã§ã³åŽã§ã¯éåžž window.postMessage ãžã®åŒã³åºããèŠãããcontent script åŽã§ã¯ window.addEventListener ã®ãããªãªã¹ããŒãèŠãããŸãããã ããextension ã web ã¢ããªã±ãŒã·ã§ã³ã«å¯Ÿã㊠Post Message ãéãïŒãã®ãã web åŽã¯ãããäºæããå¿
èŠãããïŒããåã« web ã«æ°ããã¹ã¯ãªãããèªã¿èŸŒãŸããããšãããåŸãŸãã
Inside the extension
éåžžãæ¡åŒµå
ã§ã¡ãã»ãŒãžãéãã«ã¯ chrome.runtime.sendMessage ã䜿ããïŒé垞㯠background script ã§åŠçãããïŒãåãåã£ãŠåŠçããããã«ã¯ chrome.runtime.onMessage.addListener ãåŒãã§ãªã¹ããŒãç»é²ããŸãã
åçºã®ã¡ãã»ãŒãžéä¿¡ã®ä»£ããã« chrome.runtime.connect() ã䜿ã£ãŠæç¶çãªæ¥ç¶ãäœãããšãå¯èœã§ã以äžã®äŸã®ããã« ã¡ãã»ãŒãžãéåä¿¡ ããããã«äœ¿ããŸãã
chrome.runtime.connect() example
```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` èšå®ã§èš±å¯ããã Webã¢ããªãšå€éšã®ãã©ãŠã¶æ¡åŒµæ©èœã¯ãæ¬¡ã®æ¹æ³ã§ãªã¯ãšã¹ããéä¿¡ã§ããŸã :**
```javascript
chrome.runtime.sendMessage(extensionId, ...
å¿ èŠã«å¿ããŠextension IDãèšèŒããã
Native Messaging
ããã¯ã°ã©ãŠã³ãã¹ã¯ãªããã¯ã·ã¹ãã å ã®ãã€ããªãšéä¿¡ããããšãå¯èœã§ããããã®éä¿¡ãé©åã«ä¿è·ãããŠããªãå ŽåãRCEs ã®ãããªé倧ãªè匱æ§ãæãå¯èœæ§ããããŸãã More on this later.
chrome.runtime.sendNativeMessage(
"com.my_company.my_application",
{ text: "Hello" },
function (response) {
console.log("Received " + response)
}
)
Web âïž Content Script Communication
content scripts ãåäœããç°å¢ãšãã¹ãããŒãžãååšããç°å¢ã¯äºãã«åé¢ãããŠãããéé¢ã確ä¿ãããŠããŸãããšã¯ããããã®éé¢ç¶æ ã§ãäž¡è ã¯å ±æãªãœãŒã¹ã§ãã Document Object Model (DOM) ã«å¯ŸããŠæäœãè¡ãããšãã§ããŸãããã¹ãããŒãžã content script ãšéä¿¡ããããŸã㯠content script ãä»ããŠæ¡åŒµæ©èœãšéæ¥çã«éä¿¡ããã«ã¯ãäž¡è ãå©çšã§ãã DOM ãéä¿¡ãã£ãã«ãšããŠäœ¿çšããå¿ èŠããããŸãã
Post Messages
// 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
)
document.getElementById("theButton").addEventListener(
"click",
() => {
window.postMessage(
{ type: "FROM_PAGE", text: "Hello from the webpage!" },
"*"
)
},
false
)
A secure Post Message communication should check the authenticity of the received message, this can be done checking:
event.isTrusted: This is True only if the event was triggered by a users action- The content script might expecting a message only if the user performs some action
- origin domain: might expecting a message only allowlist of domains.
- If a regex is used, be very careful
- Source:
received_message.source !== windowcan be used to check if the message was from the same window where the Content Script is listening.
The previous checks, even if performed, could be vulnerable, so check in the following page potential Post Message bypasses:
Iframe
Another possible way of communication might be through Iframe URLs, you can find an example in:
DOM
This isnât âexactlyâ a communication way, but the web and the content script will have access to the web DOM. So, if the content script is reading some information from it, trusting the web DOM, the web could modify this data (because the web shouldnât be trusted, or because the web is vulnerable to XSS) and compromise the Content Script.
You can also find an example of a DOM based XSS to compromise a browser extension in:
Content Script âïž Background Script Communication
A Content Script can use the functions runtime.sendMessage() or tabs.sendMessage() to send a one-time JSON-serializable message.
To handle the response, use the returned Promise. Although, for backward compatibility, you can still pass a callback as the last argument.
Sending a request from a content script looks like this:
;(async () => {
const response = await chrome.runtime.sendMessage({ greeting: "hello" })
// do something with response here, not outside the function
console.log(response)
})()
ãªã¯ãšã¹ããextensionïŒéåžžã¯background scriptïŒããéä¿¡ããã
éžæããã¿ãå
ã®content scriptã«ã¡ãã»ãŒãžãéä¿¡ããäŸïŒ
// 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 ã® ã€ãã³ããªã¹ã㌠ãèšå®ããå¿ èŠããããŸãããã㯠content script ã extension page ããã§ãåãã§ãã
// 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() ã¯åæçã«å®è¡ãããŠããŸãããonMessage ã€ãã³ããã³ãã©ã sendResponse() ãéåæã§å®è¡ãããã倿Žããã«ã¯ãreturn true; ãå¿
ãå«ããå¿
èŠããããŸãã
éèŠãªç¹ãšããŠãè€æ°ã®ããŒãžã onMessage ã€ãã³ããåãåãèšå®ã«ãªã£ãŠããå Žåãç¹å®ã®ã€ãã³ãã«å¯ŸããŠæåã« sendResponse() ãå®è¡ããããŒãž ã®ã¿ãã¬ã¹ãã³ã¹ãæå¹ã«è¿ãããšãã§ããŸããåãã€ãã³ãã«å¯Ÿãããã以éã®ã¬ã¹ãã³ã¹ã¯ç¡èŠãããŸãã
æ°ããæ¡åŒµæ©èœãäœæããéã¯ãcallbacks ãã promises ã䜿ãããšãæšå¥šããŸããcallback ã䜿ãå ŽåãsendResponse() ã¯åæã³ã³ããã¹ãå
ã§çŽæ¥å®è¡ãããå ŽåããŸãã¯ã€ãã³ããã³ãã©ã true ãè¿ããŠéåæåŠçã瀺ããŠããå Žåã«ã®ã¿æå¹ãšèŠãªãããŸããã©ã®ãã³ãã©ã true ãè¿ããªããããã㯠sendResponse() ãã¡ã¢ãªããè§£æŸïŒã¬ããŒãžã³ã¬ã¯ã·ã§ã³ïŒããããšãsendMessage() ã«æž¡ãã callback ã¯ããã©ã«ãã§åŒã³åºãããŸãã
Native Messaging
ãã©ãŠã¶æ¡åŒµã¯ãbinaries in the system via stdin ãšéä¿¡ããããšãã§ããŸããã¢ããªã±ãŒã·ã§ã³ã¯ãã®æšã瀺ã json ãã€ã³ã¹ããŒã«ããå¿ èŠãããã以äžã®ãã㪠json ãé 眮ããŸãïŒ
{
"name": "com.my_company.my_application",
"description": "My Application",
"path": "C:\\Program Files\\My Application\\chrome_native_messaging_host.exe",
"type": "stdio",
"allowed_origins": ["chrome-extension://knldjmfmopnpolahpmmgbagdohdnhkik/"]
}
name ã¯ããã©ãŠã¶æ¡åŒµã® background scripts ããã¢ããªã±ãŒã·ã§ã³ãšéä¿¡ããããã« runtime.connectNative() ãŸã㯠runtime.sendNativeMessage() ã«æž¡ãããæååã§ããpath ã¯ãã€ããªãžã®ãã¹ã§ãtype ã¯æå¹ãªå€ã 1 ã€ã ãã§ stdioïŒstdin ãš stdout ã䜿çšïŒã§ããallowed_origins ã¯ã¢ã¯ã»ã¹ã§ããæ¡åŒµæ©èœã瀺ãïŒã¯ã€ã«ãã«ãŒãã¯äœ¿çšã§ããŸããïŒã
Chrome/Chromium ã¯ãã® json ã Windows registry ã macOS ããã³ Linux ã®ããã€ãã®ãã¹ã§æ€çŽ¢ããŸãïŒè©³çŽ°ã¯ docs ãåç §ïŒã
Tip
ãã©ãŠã¶æ¡åŒµã§ãããã®éä¿¡ãå©çšããããã«
nativeMessaingpermission ã宣èšããŠããå¿ èŠããããŸãã
以äžã¯ãbackground script ã native application ã«ã¡ãã»ãŒãžãéãã³ãŒãã®äŸã§ãïŒ
chrome.runtime.sendNativeMessage(
"com.my_company.my_application",
{ text: "Hello" },
function (response) {
console.log("Received " + response)
}
)
In this blog postãnative messagesãæªçšããè匱ãªãã¿ãŒã³ãææ¡ãããŠããŸã:
- Browser extensionãcontent scriptçšã«ã¯ã€ã«ãã«ãŒããã¿ãŒã³ãæã£ãŠããã
- Content scriptã
postMessageã¡ãã»ãŒãžãsendMessageã䜿ã£ãŠbackground scriptã«æž¡ãã - Background scriptããã®ã¡ãã»ãŒãžã
sendNativeMessageã䜿ã£ãŠnative applicationã«æž¡ãã - Native applicationãã¡ãã»ãŒãžãå±éºã«åŠçããã³ãŒãå®è¡ã«ã€ãªããã
ãããŠããã®äžã§ ä»»æã®ããŒãžããbrowser extensionãæªçšããŠRCEã«è³ãäŸã説æãããŠããŸãã
Sensitive Information in Memory/Code/Clipboard
ãã Browser Extension ã æ©å¯æ å ±ãã¡ã¢ãªå ã«ä¿åããŠãã ãšãïŒç¹ã« Windows ãã·ã³ã§ã¯ïŒããã ãã³ã ããããã®æ å ±ã æ€çŽ¢ ãããå¯èœæ§ããããŸãã
ãããã£ãŠãBrowser Extension ã®ã¡ã¢ãªã¯ å®å šãšã¯èŠãªãããªã ãããcredentials ã mnemonic phrases ã®ãã㪠æ©å¯æ å ± ã ä¿åãã¹ãã§ã¯ãªãã
ãã¡ãããã³ãŒãã«æ©å¯æ å ±ãå ¥ããªãã§ãã ããããããããšãã㯠public ã«ãªããŸãã
ãã©ãŠã¶ããã¡ã¢ãªããã³ãããã«ã¯ãããã»ã¹ã®ã¡ã¢ãªããã³ã ãããããã©ãŠã¶æ¡åŒµã® settings ã«è¡ã Inspect pop-up ãã¯ãªã㯠-> Memory ã»ã¯ã·ã§ã³ -> Take a snaphost -> CTRL+F ã§ã¹ãããã·ã§ããå
ãæ€çŽ¢ããŠæ©å¯æ
å ±ãæ¢ãããšãã§ããŸãã
ããã«ãmnemonic keys ããã¹ã¯ãŒãã®ãããªé«åºŠã«æ©å¯æ§ã®é«ãæ å ±ã¯ ã¯ãªããããŒãã«ã³ããŒã§ããªãããã«ãã¹ãïŒå°ãªããšãæ°ç§åŸã«ã¯ãªããããŒãããåé€ããïŒã§ãããããªããšã¯ãªããããŒããç£èŠããããã»ã¹ãããããååŸã§ããŠããŸããŸãã
Loading an Extension in the Browser
- Download the Browser Extension & unzipped
- Go to
chrome://extensions/and enable theDeveloper Mode - Click the
Load unpackedbutton
In Firefox you go to about:debugging#/runtime/this-firefox and click Load Temporary Add-on button.
Getting the source code from the store
The source code of a Chrome extension can be obtained through various methods. Below are detailed explanations and instructions for each option.
Download Extension as ZIP via Command Line
The source code of a Chrome extension can be downloaded as a ZIP file using the command line. This involves using curl to fetch the ZIP file from a specific URL and then extracting the contents of the ZIP file to a directory. Here are the steps:
- Replace
"extension_id"with the actual ID of the extension. - Execute the following commands:
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 ãŠã§ããµã€ãã䜿çšãã
CRX Viewer æ¡åŒµæ©èœã䜿çšãã
ãã1ã€ã®äŸ¿å©ãªæ¹æ³ã¯ãChrome Extension Source Viewer ã䜿ãããšã§ããããã¯ãªãŒãã³ãœãŒã¹ãããžã§ã¯ãã§ãChrome Web Store ããã€ã³ã¹ããŒã«ã§ããŸãããã¥ãŒã¯ãŒã®ãœãŒã¹ã³ãŒãã¯ãã® GitHub repository ã§å ¥æå¯èœã§ãã
ããŒã«ã«ã«ã€ã³ã¹ããŒã«ãããæ¡åŒµæ©èœã®ãœãŒã¹ã衚瀺ãã
Chrome ã«ããŒã«ã«ã«ã€ã³ã¹ããŒã«ãããæ¡åŒµæ©èœã調ã¹ãããšãã§ããŸããæ¹æ³ã¯æ¬¡ã®ãšããã§ãã
chrome://version/ã«ã¢ã¯ã»ã¹ããâProfile Pathâ ãã£ãŒã«ãã確èªã㊠Chrome ã®ããŒã«ã«ãããã¡ã€ã«ãã£ã¬ã¯ããªã«ã¢ã¯ã»ã¹ããŸãã- ãããã¡ã€ã«ãã£ã¬ã¯ããªå
ã®
Extensions/ãµããã©ã«ãã«ç§»åããŸãã - ãã®ãã©ã«ãã«ã¯ãéåžžèªã¿ããã圢åŒã§ãœãŒã¹ã³ãŒããå«ããã¹ãŠã®ã€ã³ã¹ããŒã«æžã¿æ¡åŒµæ©èœãæ ŒçŽãããŠããŸãã
æ¡åŒµæ©èœãç¹å®ããã«ã¯ãID ãååã«ãããã³ã°ã§ããŸã:
about:extensionsããŒãžã§ Developer Mode ãæå¹ã«ããŠãåæ¡åŒµæ©èœã® ID ã確èªããŸãã- åæ¡åŒµæ©èœã®ãã©ã«ãå
ã«ãã
manifest.jsonãã¡ã€ã«ã«ã¯èªã¿ãããnameãã£ãŒã«ããå«ãŸããŠãããæ¡åŒµæ©èœã®ç¹å®ã«åœ¹ç«ã¡ãŸãã
ãã¡ã€ã«ã¢ãŒã«ã€ããŸãã¯ã¢ã³ããã«ã䜿çšãã
Chrome Web Store ã«ã¢ã¯ã»ã¹ããŠæ¡åŒµæ©èœãããŠã³ããŒãããŸãããã¡ã€ã«ã¯ .crx æ¡åŒµåã«ãªããŸãããã¡ã€ã«æ¡åŒµåã .crx ãã .zip ã«å€æŽããŸããWinRARã7-Zip ãªã©ä»»æã®ãã¡ã€ã«ã¢ãŒã«ã€ãã䜿ã£ãŠ ZIP ã®äžèº«ãå±éããŠãã ããã
Chrome ã§ Developer Mode ã䜿çšãã
Chrome ãéããchrome://extensions/ ã«ç§»åããŸããå³äžã§ âDeveloper modeâ ãæå¹ã«ããŸããâLoad unpacked extensionâŠâ ãã¯ãªãã¯ããŸããæ¡åŒµæ©èœã®ãã£ã¬ã¯ããªã«ç§»åããŸããããã¯ãœãŒã¹ã³ãŒããããŠã³ããŒãããããã§ã¯ãããŸããããæ¢ã«ããŠã³ããŒãæžã¿ãŸãã¯éçºäžã®æ¡åŒµæ©èœã®ã³ãŒãã衚瀺ã»ç·šéããã®ã«äŸ¿å©ã§ãã
Chrome extension manifest dataset
è匱ãªãã©ãŠã¶æ¡åŒµæ©èœãèŠã€ããããšããå Žåãhttps://github.com/palant/chrome-extension-manifests-dataset ã䜿ãããã® manifest ãã¡ã€ã«ãæœåšçã«è匱ãªç®æã«ã€ããŠãã§ãã¯ã§ããŸããããšãã°ããŠãŒã¶ãŒæ°ã 25000 ãè¶
ããcontent_scripts ãæã¡ãããŒããã·ã§ã³ã« nativeMessaing ãå«ãŸããæ¡åŒµæ©èœããã§ãã¯ããã«ã¯:
# Query example from https://spaceraccoon.dev/universal-code-execution-browser-extensions/
node query.js -f "metadata.user_count > 250000" "manifest.content_scripts?.length > 0 && manifest.permissions?.includes('nativeMessaging')"
Post-exploitation: Forced extension load & persistence (Windows)
Chromium ããŠãŒã¶ããšã® Preferences ãçŽæ¥ç·šéããæ£åœãª HMACs ãåœé ããŠããã¯ãã¢åããã¹ãã«ã¹ææ³ãããã«ããããã©ãŠã¶ã¯ããã³ããããã©ã°ãªãã§ä»»æã® unpacked extension ãåãå ¥ããŠæå¹åããŸãã
Forced Extension Load Preferences Mac Forgery Windows
Security Audit Checklist
ãã©ãŠã¶æ¡åŒµæ©èœã¯æ»æå¯Ÿè±¡ãæ¯èŒçéå®ãããŠãããã®ã®ãäžéšã«ã¯è匱æ§ãããŒããã³ã°ã®äœå°ãååšããŸãã以äžã¯æãäžè¬çãªãã§ãã¯é ç®ã§ã:
- Limit as much as possible requested
permissions - Limit as much as possible
host_permissions - Use a strong
content_security_policy - Limit as much as possible the
externally_connectable, if none is needed and possible, do not leave it by default, specify{} - If URL vulnerable to XSS or to takeover is mentioned here, an attacker will be able to send messages to the background scripts directly. Very powerful bypass.
- Limit as much as possible the
web_accessible_resources, even empty if possible. - If
web_accessible_resourcesis not none, check for ClickJacking - If any communication occurs from the extension to the web page, check for XSS vulnerabilities caused in the communication.
- If Post Messages are used, check for Post Message vulnerabilities.
- If the Content Script access DOM details, check that they arenât introducing a XSS if they get modified by the web
- Make a special emphasis if this communication is also involved in the Content Script -> Background script communication
- If the background script is communicating via native messaging check the communication is secure and sanitized
- Sensitive information shouldnât be stored inside the Browser Extension code
- Sensitive information shouldnât be stored inside the Browser Extension memory
- Sensitive information shouldnât be stored inside the file system unprotected
Browser Extension Risks
- The app https://crxaminer.tech/ analyzes some data like the permissions browser extension requests to give a risk level of using the browser extension.
Tools
Tarnish
- Pulls any Chrome extension from a provided Chrome webstore link.
- manifest.json viewer: simply displays a JSON-prettified version of the extensionâs manifest.
- Fingerprint Analysis: Detection of web_accessible_resources and automatic generation of Chrome extension fingerprinting JavaScript.
- Potential Clickjacking Analysis: Detection of extension HTML pages with the web_accessible_resources directive set. These are potentially vulnerable to clickjacking depending on the purpose of the pages.
- Permission Warning(s) viewer: which shows a list of all the Chrome permission prompt warnings which will be displayed upon a user attempting to install the extension.
- Dangerous Function(s): shows the location of dangerous functions which could potentially be exploited by an attacker (e.g. functions such as innerHTML, chrome.tabs.executeScript).
- Entry Point(s): shows where the extension takes in user/external input. This is useful for understanding an extensionâs surface area and looking for potential points to send maliciously-crafted data to the extension.
- Both the Dangerous Function(s) and Entry Point(s) scanners have the following for their generated alerts:
- Relevant code snippet and line that caused the alert.
- Description of the issue.
- A âView Fileâ button to view the full source file containing the code.
- The path of the alerted file.
- The full Chrome extension URI of the alerted file.
- The type of file it is, such as a Background Page script, Content Script, Browser Action, etc.
- If the vulnerable line is in a JavaScript file, the paths of all of the pages where it is included as well as these pageâs type, and web_accessible_resource status.
- Content Security Policy (CSP) analyzer and bypass checker: This will point out weaknesses in your extensionâs CSP and will also illuminate any potential ways to bypass your CSP due to whitelisted CDNs, etc.
- Known Vulnerable Libraries: This uses Retire.js to check for any usage of known-vulnerable JavaScript libraries.
- Download extension and formatted versions.
- Download the original extension.
- Download a beautified version of the extension (auto prettified HTML and JavaScript).
- Automatic caching of scan results, running an extension scan will take a good amount of time the first time you run it. However the second time, assuming the extension hasnât been updated, will be almost instant due to the results being cached.
- Linkable Report URLs, easily link someone else to an extension report generated by tarnish.
Neto
Project Neto is a Python 3 package conceived to analyse and unravel hidden features of browser plugins and extensions for well-known browsers such as Firefox and Chrome. It automates the process of unzipping the packaged files to extract these features from relevant resources in a extension like manifest.json, localization folders or Javascript and HTML source files.
References
- Thanks to @naivenom for the help with this methodology
- https://www.cobalt.io/blog/introduction-to-chrome-browser-extension-security-testing
- https://palant.info/2022/08/10/anatomy-of-a-basic-extension/
- https://palant.info/2022/08/24/attack-surface-of-extension-pages/
- https://palant.info/2022/08/31/when-extension-pages-are-web-accessible/
- https://help.passbolt.com/assets/files/PBL-02-report.pdf
- https://developer.chrome.com/docs/extensions/develop/concepts/content-scripts
- https://developer.chrome.com/docs/extensions/mv2/background-pages
- https://thehackerblog.com/kicking-the-rims-a-guide-for-securely-writing-and-auditing-chrome-extensions/
- https://gist.github.com/LongJohnCoder/9ddf5735df3a4f2e9559665fb864eac0
Tip
AWSãããã³ã°ãåŠã³ãå®è·µããïŒ
HackTricks Training AWS Red Team Expert (ARTE)
GCPãããã³ã°ãåŠã³ãå®è·µããïŒHackTricks Training GCP Red Team Expert (GRTE)
Azureãããã³ã°ãåŠã³ãå®è·µããïŒ
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricksããµããŒããã
- ãµãã¹ã¯ãªãã·ã§ã³ãã©ã³ã確èªããŠãã ããïŒ
- **ð¬ Discordã°ã«ãŒããŸãã¯ãã¬ã°ã©ã ã°ã«ãŒãã«åå ããããTwitter ðŠ @hacktricks_liveããã©ããŒããŠãã ããã
- HackTricksããã³HackTricks Cloudã®GitHubãªããžããªã«PRãæåºããŠãããã³ã°ããªãã¯ãå ±æããŠãã ããã


