Browser Extension Pentesting Methodology
Tip
AWS Hacking’i öğrenin ve pratik yapın:
HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking’i öğrenin ve pratik yapın:HackTricks Training GCP Red Team Expert (GRTE)
Azure Hacking’i öğrenin ve pratik yapın:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- 💬 Discord grubuna veya telegram grubuna katılın ya da Twitter’da bizi takip edin 🐦 @hacktricks_live.**
- Hacking ipuçlarını paylaşmak için HackTricks ve HackTricks Cloud github reposuna PR gönderin.
Temel Bilgiler
Tarayıcı uzantıları JavaScript ile yazılır ve arka planda tarayıcı tarafından yüklenir. Kendi DOM’u vardır ancak diğer sitelerin DOM’larıyla etkileşime girebilir. Bu, başka sitelerin gizliliğini, bütünlüğünü ve kullanılabilirliğini (CIA) tehlikeye atabileceği anlamına gelir.
Ana Bileşenler
Uzantı düzenleri görselleştirildiğinde en iyi şekilde anlaşılır ve üç bileşenden oluşur. Her bir bileşeni derinlemesine inceleyelim.
 (1) (1).png)
Content Scripts
Her content script, tek bir web sayfasının DOM’una doğrudan erişir ve bu nedenle potansiyel olarak kötü amaçlı girdiye maruz kalır. Ancak content script’in extension core’a mesaj gönderme yeteneği dışında başka bir izni yoktur.
Extension Core
Extension core, uzantının çoğu ayrıcalığını/erişimini içerir, ancak extension core yalnızca web içeriğiyle XMLHttpRequest ve content script’ler aracılığıyla etkileşime girebilir. Ayrıca extension core’un host makineye doğrudan erişimi yoktur.
Native Binary
Uzantı, kullanıcının tam ayrıcalıklarıyla host makineye erişebilen bir native binary’e izin verir. Native binary, Flash ve diğer tarayıcı plug-in’leri tarafından kullanılan standart Netscape Plugin Application Programming Interface (NPAPI) aracılığıyla extension core ile etkileşime girer.
Boundaries
Caution
Kullanıcının tam ayrıcalıklarını elde etmek için bir saldırganın, content script’ten extension core’a ve extension core’dan native binary’e kötü amaçlı girdiyi aktaracak şekilde uzantıyı ikna etmesi gerekir.
Uzantının her bileşeni birbirinden güçlü koruyucu sınırlarla ayrılmıştır. Her bileşen ayrı bir işletim sistemi süreci içinde çalışır. Content script’ler ve extension core’lar, çoğu işletim sistemi servisi tarafından erişilemeyen sandbox süreçlerinde çalışır.
Ayrıca, content script’ler ilişkili oldukları web sayfalarından ayrı bir JavaScript heap’inde çalışarak ayrılır. Content script ile web sayfası aynı temel DOM’a erişim sağlar, ancak ikisi asla JavaScript pointers paylaşmaz; bu da JavaScript fonksiyonelliğinin leak edilmesini önler.
manifest.json
Bir Chrome uzantısı, .crx file extension uzantılı bir ZIP klasörüdür. Uzantının çekirdeği, klasörün kökündeki manifest.json dosyasıdır; bu dosya düzeni, izinleri ve diğer yapılandırma seçeneklerini belirtir.
Örnek:
{
"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
Content scripts, kullanıcı eşleşen bir sayfaya her yönlendiğinde yüklenir; bizim örneğimizde https://example.com/* ifadesiyle eşleşen ve *://*/*/business* regex’ine uymayan herhangi bir sayfa. Bunlar sayfanın kendi scriptleri gibi çalışır ve sayfanın Document Object Model (DOM) üzerinde keyfi erişime sahiptir.
"content_scripts": [
{
"js": [
"script.js"
],
"matches": [
"https://example.com/*",
"https://www.example.com/*"
],
"exclude_matches": ["*://*/*business*"],
}
],
Daha fazla URL’yi dahil etmek veya hariç tutmak için include_globs ve exclude_globs kullanmak da mümkündür.
Bu, extension’s storage’taki message değerini almak için the storage API kullanıldığında sayfaya bir ‘explain’ butonu ekleyecek örnek bir content script’tir.
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)
Bu düğmeye tıklandığında, içerik scripti runtime.sendMessage() API kullanarak uzantı sayfalarına bir mesaj gönderir. Bunun nedeni içerik scriptinin API’lere doğrudan erişimdeki sınırlamasıdır; storage bu nadir istisnalardan biridir. Bu istisnaların ötesindeki işlevsellikler için, içerik scriptlerinin iletişim kurabildiği uzantı sayfalarına mesaj gönderilir.
Warning
Tarayıcıya bağlı olarak, content script’in yetenekleri biraz değişiklik gösterebilir. Chromium tabanlı tarayıcılar için yetenekler listesi Chrome Developers documentation adresinde bulunabilir, Firefox için ana kaynak MDN’dir.
Ayrıca content scriptlerinin background scriptlerle iletişim kurma yeteneğine sahip olduğu ve böylece eylemler gerçekleştirebildiği ve yanıtları iletebildiği de kayda değerdir.
Chrome’da content scriptleri görüntülemek ve hata ayıklamak için Chrome developer tools menüsüne Options > More tools > Developer tools üzerinden erişilebilir veya Ctrl + Shift + I tuşlarına basılabilir.
Geliştirici araçları açıldıktan sonra Source tab tıklanmalı, ardından Content Scripts tab seçilmelidir. Bu, çeşitli uzantıların çalışan content scriptlerini gözlemlemeye ve yürütme akışını izlemek için breakpoint’ler ayarlamaya olanak tanır.
Enjekte edilen content scripts
Tip
Unutmayın ki Content Scripts zorunlu değildir; çünkü dinamik olarak script enjekte etmek ve web sayfalarına programatik olarak enjekte etmek de
tabs.executeScriptile mümkündür. Bu, aslında daha ayrıntılı kontroller sağlar.
Bir content script’in programatik olarak enjekte edilebilmesi için, uzantının scriptlerin enjekte edileceği sayfa için host permissions olması gerekir. Bu izinler, uzantının manifestinde isteyerek sağlanabilir veya geçici olarak activeTab aracılığıyla temin edilebilir.
activeTab tabanlı örnek uzantı
{
"name": "My extension",
...
"permissions": [
"activeTab",
"scripting"
],
"background": {
"service_worker": "background.js"
},
"action": {
"default_title": "Action Button"
}
}
- Tıklanınca Inject a JS file:
// 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"],
})
})
- Bir fonksiyon enjekte et tıklandığında:
//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,
})
})
Scripting izinleriyle örnek
// 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" })
Daha fazla URL’yi dahil etmek veya hariç tutmak için include_globs ve exclude_globs kullanılabilir.
İçerik Scriptleri run_at
run_at alanı JavaScript dosyalarının web sayfasına ne zaman enjekte edileceğini kontrol eder. Tercih edilen ve varsayılan değer "document_idle"’dır.
Olası değerler şunlardır:
document_idle: Mümkün olduğuncadocument_start:css’ten gelen dosyalardan sonra, ancak diğer herhangi bir DOM oluşturulmadan veya başka bir script çalıştırılmadan önce.document_end: DOM tamamlandıktan hemen sonra, ancak resimler ve çerçeveler gibi alt kaynaklar yüklenmeden önce.
Aracılığıyla manifest.json
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["https://*.example.com/*"],
"run_at": "document_idle",
"js": ["contentScript.js"]
}
],
...
}
Aracılığıyla service-worker.js
chrome.scripting.registerContentScripts([
{
id: "test",
matches: ["https://*.example.com/*"],
runAt: "document_idle",
js: ["contentScript.js"],
},
])
background
İçerik scriptleri tarafından gönderilen mesajlar, uzantının bileşenlerini koordine etmede merkezi bir rol oynayan arka plan sayfası tarafından alınır. Özellikle, arka plan sayfası uzantının ömrü boyunca kalıcıdır ve doğrudan kullanıcı etkileşimi olmadan sessizce çalışır. Kendi Belge Nesne Modeli (DOM)’una sahiptir; bu, karmaşık etkileşimler ve durum yönetimi sağlar.
Önemli Noktalar:
- Arka Plan Sayfası Rolü: Uzantı için sinir merkezi görevi görerek uzantının çeşitli parçaları arasında iletişim ve koordinasyonu sağlar.
- Kalıcılık: Kullanıcı tarafından görünmez ancak uzantının işlevselliği için bütünsel bir varlıktır.
- Otomatik Oluşturma: Açıkça tanımlanmadığı takdirde tarayıcı otomatik olarak bir arka plan sayfası oluşturur. Bu otomatik oluşturulan sayfa, uzantının manifestinde belirtilen tüm arka plan scriptlerini içerecek ve arka plan görevlerinin sorunsuz çalışmasını sağlayacaktır.
Tip
Tarayıcının (açıkça belirtilmediğinde) otomatik olarak bir arka plan sayfası oluşturma kolaylığı, gerekli tüm arka plan scriptlerinin entegre edilmesini ve çalışır durumda olmasını sağlayarak uzantı kurulum sürecini basitleştirir.
Example background script:
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:
Seçenek sayfaları ve diğerleri
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 ve potansiyel bypasses hakkında daha fazla bilgi için bakınız:
Content Security Policy (CSP) Bypass
web_accessible_resources
Bir web sayfasının bir tarayıcı uzantısının sayfasına, örneğin bir .html sayfasına erişebilmesi için, bu sayfanın manifest.json içindeki web_accessible_resources alanında belirtilmiş olması gerekir.
Örneğin:
{
...
"web_accessible_resources": [
{
"resources": [ "images/*.png" ],
"matches": [ "https://example.com/*" ]
},
{
"resources": [ "fonts/*.woff" ],
"matches": [ "https://example.com/*" ]
}
],
...
}
Bu sayfalara şu şekilde bir URL ile erişilebilir:
chrome-extension://<extension-id>/message.html
In public extensions the extension-id is accesible:
.png)
Although, if the manifest.json parameter use_dynamic_url is used, this id can be dynamic.
Tip
Note that even if a page is mentioned here, it might be protected against ClickJacking thanks to the Content Security Policy. So you also need to check it (frame-ancestors bölümü) before confirming a ClickJacking attack is possible.
Being allowed to access these pages make these pages potentially vulnerable ClickJacking:
Tip
Allowing these pages to be loaded only by the uzantı and not by random URLs could prevent ClickJacking attacks.
Caution
Note that the pages from
web_accessible_resourcesand other pages of the uzantı are also capable of contacting background scripts. So if one of these pages is vulnerable to XSS it could open a bigger vulnerability.Moreover, note that you can only open pages indicated in
web_accessible_resourcesinside iframes, but from a new tab it’s possible to access any page in the uzantı knowing the extension ID. Therefore, if an XSS is found abusing same parameters, it could be abused even if the page isn’t configured inweb_accessible_resources.
externally_connectable
A per the docs, The "externally_connectable" manifest property declares which extensions and web pages can connect to your uzantı via runtime.connect and runtime.sendMessage.
- If the
externally_connectablekey is not declared in your uzantı’s manifest or it’s declared as"ids": ["*"], all extensions can connect, but no web pages can connect. - If specific IDs are specified, like in
"ids": ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"], only those applications can connect. - If matches are specified, those web apps will be able to connect:
"matches": [
"https://*.google.com/*",
"*://*.chromium.org/*",
- If it’s specified as empty:
"externally_connectable": {}, no app or web will be able to connect.
The less extensions and URLs indicated here, the smaller the attack surface will be.
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.
Communication summary
Extension <–> WebApp
To communicate between the content script and the web page post messages are usually used. Therefore, in the web application you will usually find calls to the function window.postMessage and in the content script listeners like window.addEventListener. Note however, that the extension could also communicate with the web application sending a Post Message (and therefore the web should expect it) or just make the web load a new script.
Inside the extension
Usually the function chrome.runtime.sendMessage is used to send a message inside the extension (usually handled by the background script) and in order to receive and handle it a listener is declared calling chrome.runtime.onMessage.addListener.
It’s also possible to use chrome.runtime.connect() to have a persistent connection instead of sending single messages, it’s possible to use it to send and receive messages like in the following example:
chrome.runtime.connect() örneği
```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>
Ayrıca, belirli bir sekmede bulunan content script'e background script'ten **`chrome.tabs.sendMessage`** çağırarak mesaj göndermek de mümkündür; bu çağrıda mesajın gönderileceği sekmenin **ID**'sini belirtmeniz gerekir.
### İzin verilen `externally_connectable` kaynaklardan uzantıya
**`externally_connectable` yapılandırmasında izin verilen Web uygulamaları ve harici tarayıcı uzantıları**, istekleri şu şekilde gönderebilir:
```javascript
chrome.runtime.sendMessage(extensionId, ...
Gerekli olduğunda extension ID’yi belirtin.
Native Messaging
Background scripts’in sistem içindeki binaries ile iletişim kurması mümkündür; bu iletişim doğru şekilde güvence altına alınmazsa RCEs gibi kritik zafiyetlere açık olabilir. 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’in çalıştığı ortamlar ile host sayfaların bulunduğu ortamlar birbirinden ayrılmıştır, bu da izolasyon sağlar. Bu izolasyona rağmen her ikisi de sayfanın ortak bir kaynağı olan Document Object Model (DOM) ile etkileşime girebilir. Host sayfanın content script ile veya dolaylı olarak content script aracılığıyla extension ile iletişim kurabilmesi için, her iki tarafın erişebildiği bir iletişim kanalı olarak DOM’u kullanması gerekir.
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
)
Güvenli bir Post Message iletişimi, alınan mesajın doğruluğunu kontrol etmelidir; bu şu şekilde yapılabilir:
event.isTrusted: Bu, yalnızca event bir kullanıcı eylemiyle tetiklendiğinde True olur- content script yalnızca kullanıcı bir eylem gerçekleştirdiğinde mesaj bekliyor olabilir
- origin domain: mesajı yalnızca allowlist’teki domainlerden bekliyor olabilir.
- Bir regex kullanılıyorsa çok dikkatli olun
- Source:
received_message.source !== windowifadesi, mesajın Content Script’in dinlediği aynı pencereden olup olmadığını kontrol etmek için kullanılabilir.
Yukarıdaki kontroller yapılsa bile zayıf olabilir; bu yüzden aşağıdaki sayfada potansiyel Post Message bypass’larını kontrol edin:
Iframe
Başka bir olası iletişim yolu Iframe URLs aracılığı olabilir; bir örneğini şurada bulabilirsiniz:
DOM
Bu tam olarak bir iletişim yolu değil, ancak web ile content script web DOM’una erişebilir. Yani, content script buradan bazı bilgileri okuyor ve web DOM’a güveniyorsa, web bu veriyi değiştirebilir (çünkü web’e güvenilmemeli veya web XSS’e karşı savunmasız olabilir) ve Content Script’i tehlikeye atabilir.
Ayrıca bir DOM tabanlı XSS ile browser extension’ı ele geçirme örneğini şurada bulabilirsiniz:
Content Script ↔︎ Background Script İletişimi
Bir Content Script, tek seferlik JSON-serializable bir mesaj göndermek için runtime.sendMessage() veya tabs.sendMessage() fonksiyonlarını kullanabilir.
Yanıtı (response) işlemek için dönen Promise kullanın. Ancak geriye dönük uyumluluk için hâlâ son argüman olarak bir callback geçebilirsiniz.
content script’ten istek göndermek şu şekilde görünür:
;(async () => {
const response = await chrome.runtime.sendMessage({ greeting: "hello" })
// do something with response here, not outside the function
console.log(response)
})()
İsteği extension’dan (genellikle bir background script) gönderme. Seçilmiş tab’daki content script’e mesaj gönderme örneği:
// 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)
})()
Alıcı tarafta, mesajı işlemek için bir runtime.onMessage event listener ayarlamanız gerekir. Bu, bir content script veya extension page’ten bakıldığında aynı görünür.
// 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" })
})
Vurgulanan örnekte, sendResponse() eşzamanlı olarak çalıştırıldı. onMessage olay işleyicisini sendResponse()’un asenkron çalışması için değiştirmek istiyorsanız, return true; eklemeniz gerekir.
Önemli bir husus, birden fazla sayfanın onMessage olaylarını almaya ayarlandığı senaryolarda, belirli bir olay için sendResponse()’yi ilk çalıştıran sayfanın yanıtı etkin şekilde iletebilen tek sayfa olacağıdır. Aynı olaya yapılacak sonraki yanıtlar dikkate alınmaz.
Yeni uzantılar oluştururken tercih callback’ler yerine promise’lar olmalıdır. Callback kullanımı söz konusu olduğunda, sendResponse() fonksiyonu yalnızca eşzamanlı bağlam içinde doğrudan çalıştırılırsa veya olay işleyicisi true döndürerek asenkron bir işlem olduğunu belirtirse geçerli sayılır. Hiçbir işleyici true döndürmezse veya sendResponse() fonksiyonu bellekten kaldırılırsa (garbage-collected), varsayılan olarak sendMessage() ile ilişkili callback tetiklenir.
Native Messaging
Tarayıcı uzantıları ayrıca sistemdeki ikili uygulamalarla stdin üzerinden iletişim kurmaya izin verir. Uygulama, bunun belirtildiği bir json yüklemeli; örneğin şu şekilde bir 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/"]
}
Where the name is the string passed to runtime.connectNative() or runtime.sendNativeMessage() to communicate with the application from the background scripts of the browser extension. The path is the path to the binary, there is only 1 valid type which is stdio (use stdin and stdout) and the allowed_origins indicate the extensions that can access it (and can’t have wildcard).
Chrome/Chromium will search for this json in some windows registry and some paths in macOS and Linux (more info in the docs).
Tip
The browser extension also needs the
nativeMessaingpermission declared in order to be able to use this communication.
This is how it looks like some background script code sending messages to a native application:
chrome.runtime.sendNativeMessage(
"com.my_company.my_application",
{ text: "Hello" },
function (response) {
console.log("Received " + response)
}
)
In this blog post, native messages’i kötüye kullanan bir zayıf desen öneriliyor:
- Tarayıcı eklentisi, content script için bir wildcard deseni kullanıyor.
- Content script, arka plan script’ine
postMessagemesajlarınısendMessageile iletiyor. - Arka plan script’i mesajı native uygulamaya
sendNativeMessageile geçiriyor. - Native uygulama mesajı tehlikeli şekilde işliyor ve kod yürütülmesine yol açıyor.
Ve içinde, herhangi bir sayfadan bir browser extension’ı kötüye kullanarak RCE’ye gitme örneği açıklanıyor.
Sensitive Information in Memory/Code/Clipboard
Eğer bir Tarayıcı Eklentisi hassas bilgiyi belleğinde tutuyorsa, bu bilgi dumped (özellikle Windows makinelerinde) edilebilir ve bu bilgi için aranabilir.
Bu nedenle, Tarayıcı Eklentisi belleği güvenli kabul edilmemeli ve kimlik bilgileri veya mnemonic ifadeler gibi hassas bilgiler saklanmamalıdır.
Tabii ki, hassas bilgileri koda koymayın, çünkü kod public olacaktır.
Tarayıcıdan belleği dump etmek için process memory’i dump edebilir veya tarayıcı eklentisinin ayarlarına gidip Inspect pop-up -> Memory bölümünde -> Take a snaphost ve CTRL+F ile snapshot içinde hassas bilgileri arayabilirsiniz.
Ayrıca, mnemonic anahtarlar veya parolalar gibi çok hassas bilgilerin panoya kopyalanmasına izin verilmemeli (veya en azından birkaç saniye içinde panodan silinmeli), çünkü panoyu izleyen prosesler bu bilgilere erişebilir.
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 web sitesini kullanın
CRX Viewer eklentisini kullanın
Başka kullanışlı bir yöntem, açık kaynaklı bir proje olan Chrome Extension Source Viewer’ı kullanmaktır. Chrome Web Store üzerinden kurulabilir. Viewer’ın kaynak kodu GitHub repository’de mevcuttur.
Yerel olarak yüklü eklentinin kaynak kodunu görüntüleme
Yerel olarak yüklenmiş Chrome eklentileri de incelenebilir. İşte nasıl:
chrome://version/adresini ziyaret ederek Chrome yerel profil dizinine erişin ve “Profile Path” alanını bulun.- Profil dizini içinde
Extensions/alt klasörüne gidin. - Bu klasör, genellikle kaynak kodları okunabilir formatta olmak üzere, yüklü tüm eklentileri içerir.
Eklentileri tanımlamak için ID’lerini isimlerle eşleyebilirsiniz:
about:extensionssayfasında Developer Mode’u etkinleştirerek her eklentinin ID’sini görün.- Her eklenti klasörünün içinde,
manifest.jsondosyası okunabilir birnamealanı içerir; bu, eklentiyi tanımlamaya yardımcı olur.
Bir Dosya Arşivleyici veya Unpacker kullanın
Chrome Web Store’a gidip eklentiyi indirin. Dosya .crx uzantılı olacaktır. Dosya uzantısını .crx’den .zip’e değiştirin. ZIP dosyasının içeriğini çıkarmak için herhangi bir dosya arşivleyici (ör. WinRAR, 7-Zip, vb.) kullanın.
Chrome’da Developer Mode’u kullanın
Chrome’u açın ve chrome://extensions/ adresine gidin. Sağ üstte “Developer mode“u etkinleştirin. “Load unpacked extension…”’e tıklayın. Eklentinizin dizinine gidin. Bu işlem kaynak kodunu indirmez, ancak zaten indirilmiş veya geliştirilmiş bir eklentinin kodunu görüntülemek ve değiştirmek için kullanışlıdır.
Chrome eklenti manifest veri seti
Zayıf tarayıcı eklentilerini tespit etmeye çalışmak için https://github.com/palant/chrome-extension-manifests-dataset kullanabilir ve manifest dosyalarını potansiyel olarak zayıf işaretler için kontrol edebilirsiniz. Örneğin 25000’den fazla kullanıcısı olan, content_scripts içeren ve nativeMessaing iznine sahip eklentileri kontrol etmek için:
# 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’u, her-kullanıcı için Preferences’ı doğrudan düzenleyip geçerli HMACs sahteleyerek arka kapı ile ele geçirmeye yarayan gizli bir teknik; bu, tarayıcının herhangi bir uyarı veya bayrak göstermeden rastgele bir unpacked extension’ı kabul edip etkinleştirmesine neden olur.
Forced Extension Load Preferences Mac Forgery Windows
Detecting Malicious Extension Updates (Static Version Diffing)
Supply-chain kompromizasyonları sıklıkla daha önce zararsız olan uzantılara yapılan malicious updates olarak gelir. Pratik ve düşük-gürültülü bir yaklaşım, yeni extension paketini son known-good sürümle static analysis kullanarak karşılaştırmakdır (örneğin, Assemblyline). Amaç her değişiklik yerine yüksek-sinyalli farkları yakalamaktır.
Workflow
- Her iki sürümü de gönderin (eski + yeni) aynı static-analysis profiline.
- Yeni veya güncellenmiş background/service worker scripts için işaretle (persistence + privileged logic).
- Yeni veya güncellenmiş content scripts için işaretle (DOM erişimi ve veri toplama).
manifest.jsoniçinde eklenen yeni permissions/host_permissions için işaretle.- Koddaki yeni domain’leri çıkarıp işaretle (potansiyel C2/exfil endpoint’leri).
- Yeni static-analysis tespitleri için işaretle (ör. base64 decode, cookie harvesting, network-request builders, obfuscation patterns).
- Değişen script’lerde ani entropy sıçramaları veya aykırı z-skorları gibi istatistiksel anomali’leri işaretle.
Detecting script changes accurately
- Yeni script eklendi →
manifest.jsondiff’i ile tespit et. - Mevcut script değiştirildi (manifest değişmedi) → çıkarılmış dosya ağacından dosya başına hash’leri karşılaştır (ör. Assemblyline
Extractçıktısı). Bu, mevcut worker veya content script’lere yapılan gizli güncellemeleri yakalar.
Pre-disclosure detections
Zaten bilinen IOC’lere dayanan “kolay mod” tespitlerinden kaçınmak için threat-intel-fed servisleri devre dışı bırakın ve alan adları, heuristic signature’lar, script farkları, entropy anomalileri gibi içsel sinyallere güvenin. Bu, zararlı güncellemeleri kamuya rapor edilmeden önce yakalama şansını artırır.
Example high-confidence alert logic
- Low-noise combo: yeni domain’ler + yeni static-analysis tespitleri + güncellenmiş background/service worker + güncellenmiş veya eklenmiş content scripts.
- Broader catch: yeni domain + yeni veya güncellenmiş background/service worker (daha yüksek recall, daha yüksek gürültü).
Bu workflow için önemli Assemblyline servisleri:
- Extract: uzantıyı açar ve dosya başına hash’leri verir.
- Characterize: dosya özelliklerini hesaplar (ör. entropy).
- JsJAWS / FrankenStrings / URLCreator: JS heuristiklerini, string’leri ve domain’leri yüzeye çıkarır; sürümler arasındaki farkları karşılaştırmak için kullanılır.
Security Audit Checklist
Tarayıcı Uzantılarının sınırlı bir saldırı yüzeyi olmasına rağmen, bazıları vulnerabilities veya güçlendirme (hardening) iyileştirmeleri içerebilir. Aşağıdakiler en yaygın olanlardır:
- Limit mümkün olduğunca istenen
permissions - Limit mümkün olduğunca
host_permissions - Güçlü bir
content_security_policykullan - Limit mümkün olduğunca
externally_connectable; gerek yoksa varsayılan bırakma,{}belirt - Eğer burada XSS veya takeover’a açık bir URL bahsediliyorsa, bir attacker doğrudan background script’lere message gönderebilecek. Çok güçlü bir bypass.
- Limit mümkün olduğunca
web_accessible_resources, mümkünse boş bırak - Eğer
web_accessible_resourcesnone değilse, ClickJacking için kontrol et - Eğer extension ve web page arasında herhangi bir communication oluyorsa, iletişimde oluşan XSS vulnerabilities için kontrol et
- Eğer Post Messages kullanılıyorsa, Post Message vulnerabilities** için kontrol et.**
- Eğer Content Script DOM erişiyorsa, web tarafından değiştirildiğinde XSS oluşturmamasını kontrol et
- Bu iletişim Content Script -> Background script iletişimini de içeriyorsa özel vurgu yap
- Eğer background script native messaging ile iletişim kuruyorsa, iletişimin güvenli ve sanitize edildiğini kontrol et
- Duyarlı bilgiler Browser Extension kodu içinde depolanmamalı
- Duyarlı bilgiler Browser Extension belleğinde saklanmamalı
- Duyarlı bilgiler korunmasız şekilde dosya sisteminde saklanmamalı
Browser Extension Risks
- Uygulama https://crxaminer.tech/ uzantının istediği permissions gibi bazı verileri analiz ederek uzantıyı kullanmanın risk seviyesini verir.
Tools
Tarnish
- Verilen Chrome webstore linkinden herhangi bir Chrome extension’ı çeker.
- manifest.json viewer: uzantının manifest’inin JSON-prettified sürümünü gösterir.
- Fingerprint Analysis: web_accessible_resources tespiti ve otomatik Chrome extension fingerprinting JavaScript üretimi.
- Potential Clickjacking Analysis: web_accessible_resources direktifi set edilmiş extension HTML sayfalarını tespit eder. Bu sayfalar amaçlarına bağlı olarak clickjacking’e açık olabilir.
- Permission Warning(s) viewer: kullanıcı uzantıyı kurmaya çalıştığında gösterilecek Chrome permission uyarılarının listesini gösterir.
- Dangerous Function(s): innerHTML, chrome.tabs.executeScript gibi potansiyel olarak bir attacker tarafından istismar edilebilecek tehlikeli fonksiyonların yerini gösterir.
- Entry Point(s): uzantının kullanıcı/dış giriş aldığı yerleri gösterir. Bu, uzantının yüzey alanını anlamak ve kötü amaçlı hazırlanmış verileri uzantıya göndermek için potansiyel noktaları bulmak açısından faydalıdır.
- Dangerous Function(s) ve Entry Point(s) tarayıcılarının ürettiği uyarılarda aşağıdakiler bulunur:
- Uyarıya neden olan ilgili kod snippet’i ve satır
- Sorunun açıklaması
- Kaynağı içeren dosyayı görüntülemek için “View File” butonu
- Uyarılı dosyanın yolu
- Uyarılı dosyanın tam Chrome extension URI’si
- Dosyanın türü (Background Page script, Content Script, Browser Action, vb.)
- Eğer zayıf satır bir JavaScript dosyasında ise, dahil edildiği tüm sayfaların yolları ve bu sayfaların türleri ile web_accessible_resource durumu.
- Content Security Policy (CSP) analyzer and bypass checker: Uzantının CSP’sindeki zayıflıkları gösterir ve beyaz listeye alınmış CDN’ler gibi CSP’yi bypass etme yollarını aydınlatır.
- Known Vulnerable Libraries: Bilinen-zayıf JavaScript kütüphane kullanımlarını kontrol etmek için Retire.js kullanır.
- Uzantıyı indir ve formatlanmış versiyonlarını indir.
- Orijinal uzantıyı indir.
- Beautified (otomatik prettified HTML ve JavaScript) sürümünü indir.
- Tarama sonuçlarını otomatik önbelleğe alır; aynı uzantı için ikinci tarama neredeyse anında dönebilir.
- Tarnish tarafından oluşturulan extension raporlarına link verilebilir.
Neto
Neto projesi, Firefox ve Chrome gibi bilinen tarayıcılar için browser plugin ve extension’ların gizli özelliklerini analiz edip ortaya çıkarmak üzere tasarlanmış bir Python 3 paketidir. Paketlenmiş dosyaların unzip edilmesini otomatikleştirir ve manifest.json, localization klasörleri veya Javascript ve HTML kaynak dosyaları gibi ilgili kaynaklardan bu özellikleri çıkartır.
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
- https://redcanary.com/blog/threat-detection/assemblyline-browser-extensions/
Tip
AWS Hacking’i öğrenin ve pratik yapın:
HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking’i öğrenin ve pratik yapın:HackTricks Training GCP Red Team Expert (GRTE)
Azure Hacking’i öğrenin ve pratik yapın:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- 💬 Discord grubuna veya telegram grubuna katılın ya da Twitter’da bizi takip edin 🐦 @hacktricks_live.**
- Hacking ipuçlarını paylaşmak için HackTricks ve HackTricks Cloud github reposuna PR gönderin.


