Tarayıcı Eklentisi Pentesting Metodolojisi
Reading time: 25 minutes
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ı eklentileri JavaScript ile yazılır ve tarayıcı tarafından arka planda yüklenir. Kendi DOM'u vardır ancak diğer sitelerin DOM'larıyla etkileşimde bulunabilir. Bu, diğer sitelerin gizliliğini, bütünlüğünü ve erişilebilirliğini (CIA) tehlikeye atabileceği anlamına gelir.
Ana Bileşenler
Eklenti düzenleri en iyi şekilde görselleştirildiğinde görünür ve üç bileşenden oluşur. Her bir bileşeni derinlemesine inceleyelim.
 (1) (1).png)
İçerik Scriptleri
Her içerik scripti, tek bir web sayfasının DOM'una doğrudan erişime sahiptir ve bu nedenle potansiyel olarak kötü niyetli girdi ile karşı karşıyadır. Ancak, içerik scriptinin eklenti çekirdeğine mesaj göndermenin dışında başka bir izni yoktur.
Eklenti Çekirdeği
Eklenti çekirdeği, eklentinin çoğu ayrıcalıklarını/erişimlerini içerir, ancak eklenti çekirdeği yalnızca XMLHttpRequest ve içerik scriptleri aracılığıyla web içeriği ile etkileşimde bulunabilir. Ayrıca, eklenti çekirdeğinin ana makineye doğrudan erişimi yoktur.
Yerel İkili
Eklenti, kullanıcının tam ayrıcalıklarıyla ana makineye erişebilen bir yerel ikili sağlar. Yerel ikili, Flash ve diğer tarayıcı eklentileri tarafından kullanılan standart Netscape Eklenti Uygulama Programlama Arayüzü (NPAPI) aracılığıyla eklenti çekirdeği ile etkileşimde bulunur.
Sınırlar
caution
Kullanıcının tam ayrıcalıklarını elde etmek için, bir saldırganın eklentiyi içerik scriptinden kötü niyetli girdiyi eklentinin çekirdeğine ve eklentinin çekirdeğinden yerel ikiliye geçirmesi için ikna etmesi gerekir.
Eklentinin her bir bileşeni, güçlü koruyucu sınırlarla birbirinden ayrılmıştır. Her bir bileşen, ayrı bir işletim sistemi sürecinde çalışır. İçerik scriptleri ve eklenti çekirdekleri, çoğu işletim sistemi hizmetine kapalı olan sandbox süreçlerinde çalışır.
Ayrıca, içerik scriptleri, ayrı bir JavaScript yığını içinde çalışarak ilişkili web sayfalarından ayrılır. İçerik scripti ve web sayfası, aynı temel DOM'a erişime sahiptir, ancak ikisi asla JavaScript işaretçilerini değiş tokuş etmez, bu da JavaScript işlevselliğinin sızmasını önler.
manifest.json
Bir Chrome eklentisi, .crx dosya uzantısına sahip bir ZIP klasörüdür. Eklentinin çekirdeği, klasörün kökünde bulunan manifest.json
dosyasıdır ve düzen, izinler 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
İçerik betikleri, kullanıcı eşleşen bir sayfaya gittiğinde yüklenir, bu durumda https://example.com/*
ifadesine uyan ve *://*/*/business*
regex'ine uymayan herhangi bir sayfa. Sayfanın Belge Nesne Modeli (DOM) üzerinde keyfi erişime sahip olarak sayfanın kendi betikleri gibi çalışırlar.
"content_scripts": [
{
"js": [
"script.js"
],
"matches": [
"https://example.com/*",
"https://www.example.com/*"
],
"exclude_matches": ["*://*/*business*"],
}
],
Daha fazla URL eklemek veya çıkarmak için include_globs
ve exclude_globs
kullanmak da mümkündür.
Bu, uzantının depolama alanından message
değerini almak için depolama API'sini kullanan bir açıklama butonu ekleyecek örnek bir içerik betiğidir.
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 butona tıklandığında, içerik betiği tarafından uzantı sayfalarına bir mesaj gönderilir; bu, runtime.sendMessage() API kullanılarak gerçekleştirilir. Bu, içerik betiğinin API'lere doğrudan erişimindeki sınırlamalardan kaynaklanmaktadır; storage
bu istisnalardan biridir. Bu istisnaların ötesindeki işlevler için, içerik betiklerinin iletişim kurabileceği uzantı sayfalarına mesajlar gönderilir.
warning
Tarayıcıya bağlı olarak, içerik betiğinin yetenekleri biraz farklılık gösterebilir. Chromium tabanlı tarayıcılar için yetenekler listesi Chrome Geliştiricileri belgelerinde mevcuttur ve Firefox için MDN ana kaynak olarak hizmet etmektedir.
Ayrıca, içerik betiklerinin arka plan betikleriyle iletişim kurma yeteneğine sahip olduğu ve bu sayede eylemler gerçekleştirebildiği ve yanıtları geri iletebildiği de dikkate değerdir.
Chrome'da içerik betiklerini görüntülemek ve hata ayıklamak için, Chrome geliştirici araçları menüsüne Seçenekler > Daha fazla araç > Geliştirici araçları yoluyla veya Ctrl + Shift + I tuşlarına basarak erişilebilir.
Geliştirici araçları görüntülendiğinde, Kaynak sekmesine tıklanmalı ve ardından İçerik Betikleri sekmesi seçilmelidir. Bu, çeşitli uzantılardan çalışan içerik betiklerinin gözlemlenmesini ve yürütme akışını izlemek için kesme noktalarının ayarlanmasını sağlar.
Enjekte edilmiş içerik betikleri
tip
İçerik Betikleri zorunlu değildir; ayrıca dinamik olarak betik enjekte etmek ve programatik olarak web sayfalarına enjekte etmek de mümkündür; bu, tabs.executeScript
aracılığıyla gerçekleştirilir. Bu, aslında daha detaylı kontroller sağlar.
Bir içerik betiğinin programatik olarak enjekte edilmesi için, uzantının betiklerin enjekte edileceği sayfa için host izinlerine sahip olması gerekmektedir. Bu izinler, uzantının manifestosunda talep edilerek veya geçici olarak activeTab aracılığıyla güvence altına alınabilir.
Örnek activeTab tabanlı uzantı
{
"name": "My extension",
...
"permissions": [
"activeTab",
"scripting"
],
"background": {
"service_worker": "background.js"
},
"action": {
"default_title": "Action Button"
}
}
- Tıklama ile bir JS dosyası enjekte et:
// 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"],
})
})
- Tıklamada bir fonksiyon enjekte et:
//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,
})
})
Örnek ile betik izinleri
// 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 eklemek veya çıkarmak için include_globs
ve exclude_globs
kullanmak da mümkündür.
İç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ğundadocument_start
:css
'den herhangi bir dosya yüklendikten sonra, ancak başka 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.
manifest.json
aracılığıyla
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["https://*.example.com/*"],
"run_at": "document_idle",
"js": ["contentScript.js"]
}
],
...
}
service-worker.js
üzerinden
chrome.scripting.registerContentScripts([
{
id: "test",
matches: ["https://*.example.com/*"],
runAt: "document_idle",
js: ["contentScript.js"],
},
])
background
İçerik betikleri 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 devam eder, doğrudan kullanıcı etkileşimi olmadan gizlice çalışır. Kendi Belge Nesne Modeli (DOM) vardır, bu da karmaşık etkileşimler ve durum yönetimi sağlar.
Ana Noktalar:
- Arka Plan Sayfası Rolü: Uzantının sinir merkezi olarak hareket eder, uzantının çeşitli parçaları arasında iletişim ve koordinasyonu sağlar.
- Süreklilik: Kullanıcıya görünmez, ancak uzantının işlevselliği için hayati 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 manifestosunda belirtilen tüm arka plan betiklerini içerecek şekilde, uzantının arka plan görevlerinin kesintisiz çalışmasını sağlar.
tip
Tarayıcının açıkça belirtilmediğinde otomatik olarak bir arka plan sayfası oluşturma kolaylığı, gerekli tüm arka plan betiklerinin entegre edilmesini ve çalışır durumda olmasını sağlar, uzantının kurulum sürecini kolaylaştırır.
Örnek arka plan betiği:
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request == "explain") {
chrome.tabs.create({ url: "https://example.net/explanation" })
}
})
runtime.onMessage API mesajları dinlemek için kullanılır. Bir "explain"
mesajı alındığında, tabs API kullanarak yeni bir sekmede bir sayfa açar.
Arka plan betiğini hata ayıklamak için uzantı ayrıntılarına gidip hizmet çalışanını inceleyebilirsiniz, bu, arka plan betiği ile geliştirici araçlarını açacaktır:
Seçenek sayfaları ve diğerleri
Tarayıcı uzantıları çeşitli türde sayfalar içerebilir:
- Eylem sayfaları, uzantı simgesine tıklandığında açılır menüde görüntülenir.
- Uzantının yeni bir sekmede yükleyeceği sayfalar.
- Seçenek Sayfaları: Bu sayfa tıklandığında uzantının üstünde görüntülenir. Önceki manifestoda benim durumumda bu sayfaya
chrome://extensions/?options=fadlhnelkbeojnebcbkacjilhnbjfjca
adresinden veya tıklayarak erişebildim:
.png)
Bu sayfaların, ihtiyaç duyulduğunda dinamik içerik yükledikleri için arka plan sayfaları gibi kalıcı olmadığını unutmayın. Bununla birlikte, arka plan sayfasıyla belirli yetenekleri paylaşırlar:
- İçerik Betikleri ile İletişim: Arka plan sayfasına benzer şekilde, bu sayfalar içerik betiklerinden mesaj alabilir, uzantı içinde etkileşimi kolaylaştırır.
- Uzantıya Özgü API'lere Erişim: Bu sayfalar, uzantı için tanımlanan izinlere tabi olarak uzantıya özgü API'lere kapsamlı erişim sağlar.
permissions
& host_permissions
permissions
ve host_permissions
, uzantının hangi izinlere sahip olduğunu (depolama, konum...) ve hangi web sayfalarında geçerli olduğunu belirten manifest.json
dosyasındaki girişlerdir.
Tarayıcı uzantıları oldukça ayrıcalıklı olabileceğinden, kötü niyetli bir uzantı veya ele geçirilmiş bir uzantı, saldırgana hassas bilgileri çalmak ve kullanıcıyı gözetlemek için farklı yollar sağlayabilir.
Bu ayarların nasıl çalıştığını ve nasıl kötüye kullanılabileceğini kontrol edin:
BrowExt - permissions & host_permissions
content_security_policy
Bir içerik güvenlik politikası, manifest.json
içinde de tanımlanabilir. Eğer tanımlıysa, açık bir şekilde savunmasız olabilir.
Tarayıcı uzantı sayfaları için varsayılan ayar oldukça kısıtlayıcıdır:
script-src 'self'; object-src 'self';
Daha fazla bilgi için CSP ve potansiyel bypass'lar hakkında kontrol edin:
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
dosyasındaki web_accessible_resources
alanında belirtilmesi gerekir.
Örneğin:
{
...
"web_accessible_resources": [
{
"resources": [ "images/*.png" ],
"matches": [ "https://example.com/*" ]
},
{
"resources": [ "fonts/*.woff" ],
"matches": [ "https://example.com/*" ]
}
],
...
}
Bu sayfalara şu URL'ler üzerinden erişilebilir:
chrome-extension://<extension-id>/message.html
Kamu uzantılarında extension-id erişilebilir:
.png)
Ancak, manifest.json
parametresi use_dynamic_url
kullanılıyorsa, bu id dinamik olabilir.
tip
Burada bir sayfa belirtilse bile, Content Security Policy sayesinde ClickJacking'e karşı korunmuş olabileceğini unutmayın. Bu nedenle, bir ClickJacking saldırısının mümkün olduğunu doğrulamadan önce bunu (frame-ancestors bölümü) kontrol etmeniz gerekir.
Bu sayfalara erişim izni verilmesi, bu sayfaları potansiyel olarak savunmasız ClickJacking hale getirir:
tip
Bu sayfaların yalnızca uzantı tarafından yüklenmesine ve rastgele URL'ler tarafından yüklenmesine izin vermek, ClickJacking saldırılarını önleyebilir.
caution
web_accessible_resources
sayfalarının ve uzantının diğer sayfalarının da arka plan betikleriyle iletişim kurma yeteneğine sahip olduğunu unutmayın. Bu nedenle, bu sayfalardan biri XSS'ye karşı savunmasızsa, daha büyük bir güvenlik açığı açabilir.
Ayrıca, yalnızca web_accessible_resources
içinde belirtilen sayfaları iframelerde açabileceğinizi, ancak yeni bir sekmeden uzantının ID'sini bilerek herhangi bir sayfaya erişmenin mümkün olduğunu unutmayın. Bu nedenle, aynı parametreleri kötüye kullanan bir XSS bulunursa, sayfa web_accessible_resources
içinde yapılandırılmamış olsa bile kötüye kullanılabilir.
externally_connectable
docs gereği, "externally_connectable"
manifest özelliği, hangi uzantıların ve web sayfalarının uzantınıza runtime.connect ve runtime.sendMessage aracılığıyla bağlanabileceğini belirtir.
- Eğer
externally_connectable
anahtarı uzantınızın manifestosunda belirtilmemişse veya"ids": ["*"]
olarak belirtilmişse, tüm uzantılar bağlanabilir, ancak hiçbir web sayfası bağlanamaz. - Eğer belirli ID'ler belirtilmişse, örneğin
"ids": ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"]
, yalnızca o uygulamalar bağlanabilir. - Eğer eşleşmeler belirtilmişse, o web uygulamaları bağlanabilecektir:
"matches": [
"https://*.google.com/*",
"*://*.chromium.org/*",
- Eğer boş olarak belirtilmişse:
"externally_connectable": {}
, hiçbir uygulama veya web bağlantı kuramayacaktır.
Burada belirtilen daha az uzantı ve URL, saldırı yüzeyinin daha küçük olacağı anlamına gelir.
caution
Eğer bir web sayfası XSS veya ele geçirme için externally_connectable
içinde belirtilmişse, bir saldırgan arka plan scriptine doğrudan mesaj gönderebilir, İçerik Scriptini ve CSP'yi tamamen atlayarak.
Bu nedenle, bu çok güçlü bir atlatmadır.
Dahası, eğer istemci kötü niyetli bir uzantı yüklerse, bu uzantının savunmasız uzantı ile iletişim kurmasına izin verilse bile, izin verilen bir web sayfasına XSS verisi enjekte edebilir veya WebRequest
veya DeclarativeNetRequest
API'lerini kötüye kullanarak hedef bir alanda istekleri manipüle edebilir ve bir sayfanın JavaScript dosyası isteğini değiştirebilir. (Hedef sayfadaki CSP bu saldırıları engelleyebilir). Bu fikir bu yazıdan gelmektedir.
İletişim özeti
Uzantı <--> Web Uygulaması
İçerik scripti ile web sayfası arasında iletişim kurmak için genellikle post mesajları kullanılır. Bu nedenle, web uygulamasında genellikle window.postMessage
fonksiyonuna yapılan çağrılar ve içerik scriptinde window.addEventListener
gibi dinleyiciler bulacaksınız. Ancak, uzantının ayrıca bir Post Message göndererek web uygulaması ile iletişim kurabileceğini (ve bu nedenle web'in bunu beklemesi gerektiğini) veya sadece web'in yeni bir script yüklemesini sağlayabileceğini unutmayın.
Uzantının içinde
Genellikle chrome.runtime.sendMessage
fonksiyonu uzantı içinde bir mesaj göndermek için kullanılır (genellikle background
scripti tarafından işlenir) ve bunu almak ve işlemek için bir dinleyici tanımlanır, bu da chrome.runtime.onMessage.addListener
çağrısını içerir.
Ayrıca, tekil mesajlar göndermek yerine sürekli bir bağlantı kurmak için chrome.runtime.connect()
kullanmak da mümkündür, bu, aşağıdaki örnekte olduğu gibi mesajlar göndermek ve almak için kullanılabilir:
chrome.runtime.connect()
örneği
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
})
Belirli bir sekmede bulunan bir içerik betiğine arka plan betiğinden mesaj göndermek de mümkündür. Bunun için chrome.tabs.sendMessage
çağrısı yaparak mesajı göndereceğiniz sekmenin ID'sini belirtmeniz gerekecektir.
İzin verilen externally_connectable
'dan uzantıya
externally_connectable
yapılandırmasında izin verilen web uygulamaları ve harici tarayıcı uzantıları aşağıdaki gibi istek gönderebilir:
chrome.runtime.sendMessage(extensionId, ...
Gerekli yerlerde uzantı kimliğinden bahsedilmesi gerekmektedir.
Yerel Mesajlaşma
Arka plan betikleri, sistem içindeki ikili dosyalarla iletişim kurabilir; bu iletişim düzgün bir şekilde güvence altına alınmazsa RCE'ler gibi kritik güvenlik açıklarına maruz kalabilir. Bununla ilgili daha fazla bilgi.
chrome.runtime.sendNativeMessage(
"com.my_company.my_application",
{ text: "Hello" },
function (response) {
console.log("Received " + response)
}
)
Web ↔︎ İçerik Scripti İletişimi
İçerik scriptlerinin çalıştığı ortamlar ve ana sayfaların bulunduğu yerler birbirinden ayrıdır, bu da izolasyon sağlar. Bu izolasyona rağmen, her ikisi de sayfanın Belge Nesne Modeli (DOM) ile etkileşimde bulunma yeteneğine sahiptir, bu da paylaşılan bir kaynaktır. Ana sayfanın içerik scripti ile veya içerik scripti aracılığıyla uzantı ile dolaylı olarak iletişim kurabilmesi için, her iki tarafın da erişebildiği DOM'u iletişim kanalı olarak kullanması gerekmektedir.
Post Mesajları
// 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 olayın bir kullanıcı eylemi tarafından tetiklendiği durumlarda Doğru'dur.- İçerik betiği, yalnızca kullanıcı bir eylem gerçekleştirdiğinde bir mesaj bekleyebilir.
- origin domain: yalnızca izin verilen alanlar listesi ile bir mesaj bekleyebilir.
- Bir regex kullanılıyorsa, çok dikkatli olun.
- Source:
received_message.source !== window
, mesajın Content Script'in dinlediği aynı pencereden gelip gelmediğini kontrol etmek için kullanılabilir.
Önceki kontroller, yapılsa bile, savunmasız olabilir, bu nedenle aşağıdaki sayfada potansiyel Post Message bypass'larını kontrol edin:
Iframe
İletişim için başka bir olası yol Iframe URL'leri aracılığıyla olabilir, bir örneği burada bulabilirsiniz:
DOM
Bu "tam olarak" bir iletişim yolu değildir, ancak web ve içerik betiği web DOM'una erişim sağlayacaktır. Yani, eğer içerik betiği buradan bazı bilgileri okuyorsa, web DOM'una güveniyorsa, web bu veriyi değiştirebilir (çünkü web'e güvenilmemelidir veya web XSS'ye karşı savunmasızdır) ve Content Script'i tehlikeye atabilir.
Ayrıca, bir DOM tabanlı XSS ile bir tarayıcı uzantısını tehlikeye atma örneğini burada bulabilirsiniz:
İçerik Betiği ↔︎ Arka Plan Betiği İletişimi
Bir İçerik Betiği, runtime.sendMessage() veya tabs.sendMessage() fonksiyonlarını kullanarak bir kerelik JSON-serializable bir mesaj gönderebilir.
Yanıtı işlemek için, döndürülen Promise'i kullanın. Ancak, geriye dönük uyumluluk için, son argüman olarak hala bir callback geçebilirsiniz.
Bir içerik betiğinden bir istek göndermek şöyle 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)
})()
uzantı'dan bir istek gönderme (genellikle bir arka plan betiği). Seçilen sekmedeki içerik betiğine mesaj göndermenin bir ö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ı tarafında, mesajı işlemek için bir runtime.onMessage olay dinleyicisi kurmanız gerekir. Bu, bir içerik betiği veya uzantı sayfasından 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" })
})
Öne çıkan örnekte, sendResponse()
senkron bir şekilde yürütüldü. sendResponse()
'nin asenkron yürütülmesi için onMessage
olay işleyicisini değiştirmek, return true;
eklemeyi gerektirir.
Önemli bir husus, birden fazla sayfanın onMessage
olaylarını alacak şekilde ayarlandığı senaryolarda, belirli bir olay için sendResponse()
'yi yürüten ilk sayfa yanıtı etkili bir şekilde iletebilecek tek sayfa olacaktır. Aynı olaya yönelik sonraki yanıtlar dikkate alınmayacaktır.
Yeni uzantılar oluştururken, geri çağırmalar yerine vaatlere yönelmek tercih edilmelidir. Geri çağırmaların kullanımıyla ilgili olarak, sendResponse()
fonksiyonu yalnızca senkron bağlamda doğrudan yürütüldüğünde veya olay işleyicisi asenkron bir işlemi true
döndürerek belirttiğinde geçerli kabul edilir. Hiçbir işleyici true
döndürmezse veya sendResponse()
fonksiyonu bellekten kaldırılırsa (çöp toplayıcı tarafından), sendMessage()
fonksiyonu ile ilişkili geri çağırma varsayılan olarak tetiklenecektir.
Native Messaging
Tarayıcı uzantıları, sistemdeki ikili dosyalarla stdin üzerinden iletişim kurmaya da olanak tanır. Uygulama, bunu belirten bir json yüklemelidir:
{
"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
parametresi, tarayıcı uzantısının arka plan betiklerinden uygulama ile iletişim kurmak için runtime.connectNative()
veya runtime.sendNativeMessage()
metoduna geçirilen dizedir. path
, ikili dosyanın yoludur, geçerli olan tek type
stdio'dur (stdin ve stdout kullanın) ve allowed_origins
, buna erişebilecek uzantıları belirtir (wildcard olamaz).
Chrome/Chromium, bu json'u bazı Windows kayıt defterlerinde ve macOS ile Linux'taki bazı yolları arayacaktır (daha fazla bilgi için docs bakın).
tip
Tarayıcı uzantısının bu iletişimi kullanabilmesi için nativeMessaing
izninin de tanımlanması gerekir.
İşte bir arka plan betiği kodunun, bir yerel uygulamaya mesaj göndermesi şöyle görünür:
chrome.runtime.sendNativeMessage(
"com.my_company.my_application",
{ text: "Hello" },
function (response) {
console.log("Received " + response)
}
)
In bu blog yazısında, yerel mesajları kötüye kullanan bir zayıf desen önerilmektedir:
- Tarayıcı uzantısı içerik betiği için bir joker karakter deseni vardır.
- İçerik betiği
sendMessage
kullanarak arka plan betiğinepostMessage
mesajları gönderir. - Arka plan betiği mesajı
sendNativeMessage
kullanarak yerel uygulamaya iletir. - Yerel uygulama mesajı tehlikeli bir şekilde işler, bu da kod yürütmeye yol açar.
Ve bunun içinde herhangi bir sayfadan RCE'ye geçiş yapma örneği bir tarayıcı uzantısını kötüye kullanarak açıklanmaktadır.
Bellek/Kod/Panodaki Hassas Bilgiler
Eğer bir Tarayıcı Uzantısı hassas bilgileri belleğinde saklıyorsa, bu dökülebilir (özellikle Windows makinelerinde) ve bu bilgiler için arama yapılabilir.
Bu nedenle, Tarayıcı Uzantısının belleği güvenli olarak kabul edilmemelidir ve kimlik bilgileri veya mnemonik ifadeler gibi hassas bilgiler saklanmamalıdır.
Elbette, hassas bilgileri kodun içine koymayın, çünkü bu kamusal olacaktır.
Tarayıcıdan bellek dökmek için işlem belleğini dökebilir veya tarayıcı uzantısının ayarlarına gitmek için Inspect pop-up
üzerine tıklayın -> Memory
bölümünde -> Take a snapshot
ve hassas bilgileri bulmak için CTRL+F
ile anlık görüntü içinde arama yapın.
Ayrıca, mnemonik anahtarlar veya şifreler gibi son derece hassas bilgilerin panoya kopyalanmasına izin verilmemelidir (veya en azından birkaç saniye içinde panodan kaldırılmalıdır) çünkü bu durumda panoyu izleyen işlemler bunları alabilecektir.
Tarayıcıda Bir Uzantı Yükleme
- Tarayıcı Uzantısını İndirin ve açın
chrome://extensions/
adresine gidin veGeliştirici Modu
nu etkinleştirinYüklenmemiş
butonuna tıklayın
Firefox'ta about:debugging#/runtime/this-firefox
adresine gidin ve Geçici Eklenti Yükle
butonuna tıklayın.
Mağazadan kaynak kodunu alma
Bir Chrome uzantısının kaynak kodu çeşitli yöntemlerle elde edilebilir. Aşağıda her seçenek için ayrıntılı açıklamalar ve talimatlar bulunmaktadır.
Komut Satırı ile ZIP Olarak Uzantıyı İndirme
Bir Chrome uzantısının kaynak kodu, komut satırı kullanılarak ZIP dosyası olarak indirilebilir. Bu, belirli bir URL'den ZIP dosyasını almak için curl
kullanmayı ve ardından ZIP dosyasının içeriğini bir dizine çıkarmayı içerir. İşte adımlar:
"extension_id"
kısmını uzantının gerçek ID'si ile değiştirin.- Aşağıdaki komutları çalıştırın:
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 uzantısını kullanın
Başka bir pratik yöntem, açık kaynaklı bir proje olan Chrome Extension Source Viewer'ı kullanmaktır. Chrome Web Store üzerinden yüklenebilir. Görüntüleyicinin kaynak kodu GitHub deposunda mevcuttur.
Yerel olarak yüklenmiş uzantının kaynağını görüntüleyin
Yerel olarak yüklenmiş Chrome uzantıları da incelenebilir. İşte nasıl:
chrome://version/
adresine giderek Chrome yerel profil dizininizi erişin ve "Profil Yolu" alanını bulun.- Profil dizinindeki
Extensions/
alt klasörüne gidin. - Bu klasör, genellikle okunabilir formatta kaynak kodlarıyla birlikte tüm yüklenmiş uzantıları içerir.
Uzantıları tanımlamak için, kimliklerini isimlere eşleyebilirsiniz:
- Her uzantının kimliklerini görmek için
about:extensions
sayfasında Geliştirici Modu'nu etkinleştirin. - Her uzantının klasöründe,
manifest.json
dosyası okunabilir birname
alanı içerir, bu da uzantıyı tanımlamanıza yardımcı olur.
Bir Dosya Arşivleyici veya Açıcı Kullanın
Chrome Web Store'a gidin ve uzantıyı indirin. Dosya .crx
uzantısına sahip 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 (WinRAR, 7-Zip vb.) kullanın.
Chrome'da Geliştirici Modunu Kullanın
Chrome'u açın ve chrome://extensions/
adresine gidin. Sağ üstte "Geliştirici modunu" etkinleştirin. "Paketlenmemiş uzantıyı yükle..." seçeneğine tıklayın. Uzantınızın dizinine gidin. Bu, kaynak kodunu indirmez, ancak zaten indirilmiş veya geliştirilmiş bir uzantının kodunu görüntülemek ve değiştirmek için faydalıdır.
Chrome uzantı manifest veri seti
Zayıf tarayıcı uzantılarını 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
ve nativeMessaging
iznine sahip uzantıları 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')"
Güvenlik Denetimi Kontrol Listesi
Tarayıcı Uzantıları sınırlı bir saldırı yüzeyine sahip olsalar da, bazıları zayıflıklar veya potansiyel güçlendirme iyileştirmeleri içerebilir. Aşağıdakiler en yaygın olanlardır:
-
İstenen
permissions
'ı mümkün olduğunca sınırlayın -
host_permissions
'ı mümkün olduğunca sınırlayın -
Güçlü bir
content_security_policy
kullanın -
externally_connectable
'ı mümkün olduğunca sınırlayın, eğer gerek yoksa ve mümkünse, varsayılan olarak bırakmayın,{}
belirtin - Burada XSS veya ele geçirme için zayıf bir URL belirtilmişse, bir saldırgan arka plan betiklerine doğrudan mesaj gönderebilir. Çok güçlü bir atlatma.
-
web_accessible_resources
'ı mümkün olduğunca sınırlayın, mümkünse boş bırakın. -
Eğer
web_accessible_resources
yoksa, ClickJacking için kontrol edin - Eğer herhangi bir iletişim uzantıdan web sayfasına oluyorsa, iletişimde oluşan XSS zayıflıklarını kontrol edin.
- Eğer Post Mesajları kullanılıyorsa, Post Mesaj zayıflıkları** için kontrol edin.**
- Eğer Content Script DOM detaylarına erişiyorsa, web tarafından değiştirilirse XSS girişine neden olmadıklarını kontrol edin
- Bu iletişimin Content Script -> Arka plan betiği iletişimi ile de ilgili olduğuna özel bir vurgu yapın
- Eğer arka plan betiği native messaging aracılığıyla iletişim kuruyorsa, iletişimin güvenli ve temiz olduğundan emin olun
- Hassas bilgiler Tarayıcı Uzantısı kodunun içinde saklanmamalıdır
- Hassas bilgiler Tarayıcı Uzantısı belleğinin içinde saklanmamalıdır
- Hassas bilgiler dosya sisteminde korumasız olarak saklanmamalıdır
Tarayıcı Uzantısı Riskleri
- Uygulama https://crxaminer.tech/ tarayıcı uzantısının talep ettiği izinler gibi bazı verileri analiz ederek tarayıcı uzantısını kullanmanın risk seviyesini belirler.
Araçlar
Tarnish
- Verilen bir Chrome webstore bağlantısından herhangi bir Chrome uzantısını çeker.
- manifest.json görüntüleyici: uzantının manifestosunun JSON formatında düzenlenmiş bir versiyonunu basitçe gösterir.
- Parmak İzi Analizi: web_accessible_resources tespiti ve otomatik Chrome uzantısı parmak izi JavaScript'i oluşturma.
- Potansiyel Clickjacking Analizi: web_accessible_resources direktifi ayarlanmış uzantı HTML sayfalarının tespiti. Bu sayfaların amacı doğrultusunda clickjacking'e karşı potansiyel olarak zayıf olabilirler.
- İzin Uyarısı görüntüleyici: uzantıyı yüklemeye çalışan bir kullanıcıya gösterilecek tüm Chrome izin istem uyarılarının listesini gösterir.
- Tehlikeli Fonksiyon(lar): bir saldırgan tarafından potansiyel olarak istismar edilebilecek tehlikeli fonksiyonların yerini gösterir (örneğin, innerHTML, chrome.tabs.executeScript gibi fonksiyonlar).
- Giriş Noktası(ları): uzantının kullanıcı/dış girdi aldığı yerleri gösterir. Bu, bir uzantının yüzey alanını anlamak ve kötü niyetli olarak hazırlanmış verileri uzantıya göndermek için potansiyel noktaları aramak için faydalıdır.
- Hem Tehlikeli Fonksiyon(lar) hem de Giriş Noktası(ları) tarayıcılarının ürettiği uyarılar için aşağıdakileri içerir:
- Uyarıya neden olan ilgili kod parçası ve satır.
- Sorunun açıklaması.
- Kodu içeren tam kaynak dosyasını görüntülemek için bir "Dosyayı Görüntüle" butonu.
- Uyarılan dosyanın yolu.
- Uyarılan dosyanın tam Chrome uzantısı URI'si.
- Dosyanın türü, örneğin Arka Plan Sayfası betiği, İçerik Betiği, Tarayıcı Eylemi vb.
- Eğer zayıf satır bir JavaScript dosyasındaysa, dahil edildiği tüm sayfaların yolları ile birlikte bu sayfaların türü ve web_accessible_resource durumu.
- İçerik Güvenlik Politikası (CSP) analizörü ve atlatma kontrolörü: Bu, uzantınızın CSP'sindeki zayıflıkları belirtecek ve beyaz listeye alınmış CDN'ler vb. nedeniyle CSP'nizi atlatmanın potansiyel yollarını aydınlatacaktır.
- Bilinen Zayıf Kütüphaneler: Bu, bilinen zayıf JavaScript kütüphanelerinin herhangi bir kullanımını kontrol etmek için Retire.js kullanır.
- Uzantıyı ve biçimlendirilmiş versiyonlarını indirin.
- Orijinal uzantıyı indirin.
- Uzantının güzelleştirilmiş bir versiyonunu indirin (otomatik olarak düzenlenmiş HTML ve JavaScript).
- Tarama sonuçlarının otomatik önbelleğe alınması, bir uzantı taraması çalıştırmak ilk kez çalıştırdığınızda iyi bir zaman alacaktır. Ancak ikinci kez, uzantı güncellenmemişse, sonuçların önbelleğe alınması nedeniyle neredeyse anında olacaktır.
- Bağlantılı Rapor URL'leri, başkalarına tarnish tarafından üretilen bir uzantı raporuna kolayca bağlantı vermenizi sağlar.
Neto
Neto Projesi, Firefox ve Chrome gibi tanınmış tarayıcılar için tarayıcı eklentilerinin ve uzantılarının gizli özelliklerini analiz etmek ve çözmek için tasarlanmış bir Python 3 paketidir. manifest.json
, yerelleştirme klasörleri veya JavaScript ve HTML kaynak dosyaları gibi ilgili kaynaklardan bu özellikleri çıkarmak için paketlenmiş dosyaların açılma sürecini otomatikleştirir.
Referanslar
- Bu metodolojiye yardımcı olduğu için @naivenom'a teşekkürler
- 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 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.