Browser Extension Pentesting Methodology

Support HackTricks

Basic Information

Οι επεκτάσεις προγράμματος περιήγησης είναι γραμμένες σε JavaScript και φορτώνονται από τον περιηγητή στο παρασκήνιο. Έχει το DOM της αλλά μπορεί να αλληλεπιδρά με τα DOM άλλων ιστότοπων. Αυτό σημαίνει ότι μπορεί να θέσει σε κίνδυνο την εμπιστευτικότητα, την ακεραιότητα και τη διαθεσιμότητα (CIA) άλλων ιστότοπων.

Main Components

Οι διάταξεις επεκτάσεων φαίνονται καλύτερες όταν απεικονίζονται και αποτελούνται από τρία στοιχεία. Ας δούμε κάθε στοιχείο σε βάθος.

Content Scripts

Κάθε script περιεχομένου έχει άμεση πρόσβαση στο DOM μιας μοναδικής ιστοσελίδας και είναι έτσι εκτεθειμένο σε πιθανώς κακόβουλη είσοδο. Ωστόσο, το script περιεχομένου δεν περιέχει δικαιώματα εκτός από την ικανότητα να στέλνει μηνύματα στον πυρήνα της επέκτασης.

Extension Core

Ο πυρήνας της επέκτασης περιέχει τα περισσότερα από τα προνόμια/πρόσβαση της επέκτασης, αλλά ο πυρήνας της επέκτασης μπορεί να αλληλεπιδρά μόνο με το περιεχόμενο του ιστού μέσω του XMLHttpRequest και των scripts περιεχομένου. Επίσης, ο πυρήνας της επέκτασης δεν έχει άμεση πρόσβαση στη μηχανή φιλοξενίας.

Native Binary

Η επέκταση επιτρέπει μια εγγενή δυαδική που μπορεί να πρόσβαση στη μηχανή φιλοξενίας με τα πλήρη προνόμια του χρήστη. Η εγγενής δυαδική αλληλεπιδρά με τον πυρήνα της επέκτασης μέσω του τυπικού Netscape Plugin Application Programming Interface (NPAPI) που χρησιμοποιείται από το Flash και άλλα πρόσθετα προγράμματος περιήγησης.

Boundaries

Για να αποκτήσει τα πλήρη προνόμια του χρήστη, ένας επιτιθέμενος πρέπει να πείσει την επέκταση να περάσει κακόβουλη είσοδο από το script περιεχομένου στον πυρήνα της επέκτασης και από τον πυρήνα της επέκτασης στην εγγενή δυαδική.

Κάθε στοιχείο της επέκτασης είναι χωρισμένο από το άλλο με ισχυρά προστατευτικά όρια. Κάθε στοιχείο εκτελείται σε μια ξεχωριστή διαδικασία λειτουργικού συστήματος. Τα scripts περιεχομένου και οι πυρήνες επεκτάσεων εκτελούνται σε διαδικασίες sandbox που δεν είναι διαθέσιμες στους περισσότερους υπηρεσίες λειτουργικού συστήματος.

Επιπλέον, τα scripts περιεχομένου χωρίζονται από τις σχετικές ιστοσελίδες τους εκτελώντας σε μια ξεχωριστή στοίβα JavaScript. Το script περιεχομένου και η ιστοσελίδα έχουν πρόσβαση στο ίδιο υποκείμενο DOM, αλλά οι δύο ποτέ δεν ανταλλάσσουν δείκτες JavaScript, αποτρέποντας τη διαρροή της λειτουργικότητας JavaScript.

manifest.json

Μια επέκταση Chrome είναι απλώς ένας φάκελος ZIP με μια .crx file extension. Ο πυρήνας της επέκτασης είναι το manifest.json αρχείο στη ρίζα του φακέλου, το οποίο καθορίζει τη διάταξη, τα δικαιώματα και άλλες επιλογές διαμόρφωσης.

Example:

{
"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.

Αυτό είναι ένα παράδειγμα περιεχομένου script που θα προσθέσει ένα κουμπί εξήγησης στη σελίδα όταν χρησιμοποιεί το storage API για να ανακτήσει την τιμή message από την αποθήκευση της επέκτασης.

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

Ένα μήνυμα αποστέλλεται στις σελίδες της επέκτασης από το περιεχόμενο του script όταν αυτό το κουμπί πατηθεί, μέσω της χρήσης του runtime.sendMessage() API. Αυτό οφείλεται στον περιορισμό του περιεχομένου του script στην άμεση πρόσβαση σε APIs, με το storage να είναι μία από τις λίγες εξαιρέσεις. Για λειτουργίες πέρα από αυτές τις εξαιρέσεις, τα μηνύματα αποστέλλονται στις σελίδες της επέκτασης με τις οποίες μπορούν να επικοινωνούν τα περιεχόμενα scripts.

Ανάλογα με τον περιηγητή, οι δυνατότητες του περιεχομένου του script μπορεί να διαφέρουν ελαφρώς. Για τους περιηγητές που βασίζονται σε Chromium, η λίστα δυνατοτήτων είναι διαθέσιμη στην τεκμηρίωση Chrome Developers, και για τον Firefox, η MDN χρησιμεύει ως η κύρια πηγή. Είναι επίσης αξιοσημείωτο ότι τα περιεχόμενα scripts έχουν τη δυνατότητα να επικοινωνούν με τα background scripts, επιτρέποντάς τους να εκτελούν ενέργειες και να μεταφέρουν απαντήσεις πίσω.

Για την προβολή και την αποσφαλμάτωση των περιεχομένων scripts στο Chrome, το μενού εργαλείων προγραμματιστών του Chrome μπορεί να προσπελαστεί από Επιλογές > Περισσότερα εργαλεία > Εργαλεία προγραμματιστών Ή πατώντας Ctrl + Shift + I.

Αφού εμφανιστούν τα εργαλεία προγραμματιστών, πρέπει να κάνετε κλικ στην καρτέλα Πηγή, ακολουθούμενη από την καρτέλα Περιεχόμενα Scripts. Αυτό επιτρέπει την παρακολούθηση των εκτελούμενων περιεχομένων scripts από διάφορες επεκτάσεις και την ρύθμιση σημείων διακοπής για την παρακολούθηση της ροής εκτέλεσης.

Εισαγόμενα περιεχόμενα scripts

Σημειώστε ότι Τα Περιεχόμενα Scripts δεν είναι υποχρεωτικά καθώς είναι επίσης δυνατή η δυναμική εισαγωγή scripts και η προγραμματική εισαγωγή τους σε ιστοσελίδες μέσω του tabs.executeScript. Αυτό παρέχει στην πραγματικότητα περισσότερους λεπτομερείς ελέγχους.

Για την προγραμματική εισαγωγή ενός περιεχομένου script, απαιτείται η επέκταση να έχει δικαιώματα φιλοξενίας για τη σελίδα στην οποία θα εισαχθούν τα scripts. Αυτά τα δικαιώματα μπορεί να εξασφαλιστούν είτε ζητώντας τα μέσα στο μανιφέστο της επέκτασης είτε προσωρινά μέσω του activeTab.

Παράδειγμα επέκτασης βασισμένης σε activeTab

manifest.json
{
"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"]
});
});
  • Εισάγετε μια συνάρτηση με κλικ:

//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

// 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.

Content Scripts run_at

Το πεδίο run_at ελέγχει πότε τα αρχεία JavaScript εισάγονται στη σελίδα web. Η προτιμώμενη και προεπιλεγμένη τιμή είναι το "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), επιτρέποντας πολύπλοκες αλληλεπιδράσεις και διαχείριση καταστάσεων.

Βασικά Σημεία:

  • Ρόλος Σελίδας Φόντου: Λειτουργεί ως το κέντρο ελέγχου της επέκτασης, εξασφαλίζοντας την επικοινωνία και τον συντονισμό μεταξύ των διαφόρων τμημάτων της επέκτασης.

  • Επιμονή: Είναι μια πάντα παρούσα οντότητα, αόρατη στον χρήστη αλλά αναπόσπαστο μέρος της λειτουργικότητας της επέκτασης.

  • Αυτόματη Δημιουργία: Εάν δεν έχει δηλωθεί ρητά, ο περιηγητής θα δημιουργήσει αυτόματα μια σελίδα φόντου. Αυτή η αυτόματα δημιουργημένη σελίδα θα περιλαμβάνει όλα τα σενάρια φόντου που καθορίζονται στο μανιφέστο της επέκτασης, εξασφαλίζοντας την απρόσκοπτη λειτουργία των εργασιών φόντου της επέκτασης.

Η ευκολία που παρέχει ο περιηγητής στην αυτόματη δημιουργία μιας σελίδας φόντου (όταν δεν δηλώνεται ρητά) εξασφαλίζει ότι όλα τα απαραίτητα σενάρια φόντου είναι ενσωματωμένα και λειτουργικά, απλοποιώντας τη διαδικασία ρύθμισης της επέκτασης.

Example background script:

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

Χρησιμοποιεί το runtime.onMessage API για να ακούει μηνύματα. Όταν ληφθεί ένα μήνυμα "explain", χρησιμοποιεί το tabs API για να ανοίξει μια σελίδα σε μια νέα καρτέλα.

Για να αποσφαλματώσετε το σενάριο φόντου, μπορείτε να μεταβείτε στις λεπτομέρειες της επέκτασης και να επιθεωρήσετε τον service worker, αυτό θα ανοίξει τα εργαλεία προγραμματιστή με το σενάριο φόντου:

Σελίδες επιλογών και άλλες

Οι επεκτάσεις προγράμματος περιήγησης μπορούν να περιέχουν διάφορους τύπους σελίδων:

  • Σελίδες δράσης εμφανίζονται σε ένα αναδυόμενο μενού όταν κάνετε κλικ στο εικονίδιο της επέκτασης.

  • Σελίδες που η επέκταση θα φορτώσει σε μια νέα καρτέλα.

  • Σελίδες επιλογών: Αυτή η σελίδα εμφανίζεται πάνω από την επέκταση όταν κάνετε κλικ. Στο προηγούμενο μανιφέστο, στην περίπτωσή μου, μπόρεσα να αποκτήσω πρόσβαση σε αυτή τη σελίδα στο chrome://extensions/?options=fadlhnelkbeojnebcbkacjilhnbjfjca ή κάνοντας κλικ:

Σημειώστε ότι αυτές οι σελίδες δεν είναι μόνιμες όπως οι σελίδες φόντου, καθώς φορτώνουν δυναμικά περιεχόμενο κατά την ανάγκη. Παρά τούτο, μοιράζονται ορισμένες δυνατότητες με τη σελίδα φόντου:

  • Επικοινωνία με Content Scripts: Παρόμοια με τη σελίδα φόντου, αυτές οι σελίδες μπορούν να λαμβάνουν μηνύματα από content scripts, διευκολύνοντας την αλληλεπίδραση εντός της επέκτασης.

  • Πρόσβαση σε APIs συγκεκριμένα για την επέκταση: Αυτές οι σελίδες απολαμβάνουν πλήρη πρόσβαση σε APIs συγκεκριμένα για την επέκταση, υπό την προϋπόθεση των αδειών που ορίζονται για την επέκταση.

permissions & host_permissions

permissions και host_permissions είναι καταχωρήσεις από το manifest.json που θα υποδεικνύουν ποιες άδειες έχει η επέκταση του προγράμματος περιήγησης (αποθήκευση, τοποθεσία...) και σε ποιες ιστοσελίδες.

Καθώς οι επεκτάσεις προγράμματος περιήγησης μπορεί να είναι τόσο προνομιούχες, μια κακόβουλη ή μια που έχει παραβιαστεί θα μπορούσε να επιτρέψει στον επιτιθέμενο διαφορετικούς τρόπους να κλέψει ευαίσθητες πληροφορίες και να κατασκοπεύσει τον χρήστη.

Ελέγξτε πώς λειτουργούν αυτές οι ρυθμίσεις και πώς θα μπορούσαν να καταχραστούν στο:

BrowExt - permissions & host_permissions

content_security_policy

Μια πολιτική ασφαλείας περιεχομένου μπορεί επίσης να δηλωθεί μέσα στο manifest.json. Εάν υπάρχει μία καθορισμένη, θα μπορούσε να είναι ευάλωτη.

Η προεπιλεγμένη ρύθμιση για τις σελίδες επεκτάσεων προγράμματος περιήγησης είναι μάλλον περιοριστική:

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

Για περισσότερες πληροφορίες σχετικά με το CSP και τις πιθανές παρακάμψεις, ελέγξτε:

Content Security Policy (CSP) Bypass

web_accessible_resources

Για να έχει μια ιστοσελίδα πρόσβαση σε μια σελίδα μιας Επέκτασης Περιηγητή, μια σελίδα .html για παράδειγμα, αυτή η σελίδα πρέπει να αναφέρεται στο πεδίο web_accessible_resources του manifest.json. Για παράδειγμα:

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

Αυτές οι σελίδες είναι προσβάσιμες σε URL όπως:

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

In public extensions the extension-id είναι προσβάσιμο:

Ωστόσο, αν η παράμετρος manifest.json use_dynamic_url χρησιμοποιείται, αυτό το id μπορεί να είναι δυναμικό.

Σημειώστε ότι ακόμη και αν μια σελίδα αναφέρεται εδώ, μπορεί να είναι προστατευμένη από ClickJacking χάρη στην Πολιτική Ασφαλείας Περιεχομένου. Έτσι, πρέπει επίσης να το ελέγξετε (τμήμα frame-ancestors) πριν επιβεβαιώσετε ότι είναι δυνατή μια επίθεση ClickJacking.

Η δυνατότητα πρόσβασης σε αυτές τις σελίδες καθιστά αυτές τις σελίδες πιθανώς ευάλωτες σε ClickJacking:

BrowExt - ClickJacking

Η επιτρεπόμενη φόρτωση αυτών των σελίδων μόνο από την επέκταση και όχι από τυχαίες διευθύνσεις URL θα μπορούσε να αποτρέψει επιθέσεις ClickJacking.

Σημειώστε ότι οι σελίδες από web_accessible_resources και άλλες σελίδες της επέκτασης είναι επίσης ικανές να επικοινωνούν με σενάρια φόντου. Έτσι, αν μία από αυτές τις σελίδες είναι ευάλωτη σε XSS, θα μπορούσε να ανοίξει μια μεγαλύτερη ευπάθεια.

Επιπλέον, σημειώστε ότι μπορείτε να ανοίξετε μόνο σελίδες που αναφέρονται σε web_accessible_resources μέσα σε iframes, αλλά από μια νέα καρτέλα είναι δυνατή η πρόσβαση σε οποιαδήποτε σελίδα στην επέκταση γνωρίζοντας το extension ID. Επομένως, αν βρεθεί XSS που εκμεταλλεύεται τις ίδιες παραμέτρους, θα μπορούσε να εκμεταλλευτεί ακόμη και αν η σελίδα δεν έχει ρυθμιστεί σε web_accessible_resources.

externally_connectable

Σύμφωνα με τα docs, Η ιδιότητα "externally_connectable" του manifest δηλώνει ποια extensions και ιστοσελίδες μπορούν να συνδεθούν με την επέκτασή σας μέσω runtime.connect και runtime.sendMessage.

  • Αν το externally_connectable κλειδί δεν δηλώνεται στο manifest της επέκτασής σας ή δηλώνεται ως "ids": ["*"], όλες οι επεκτάσεις μπορούν να συνδεθούν, αλλά καμία ιστοσελίδα δεν μπορεί να συνδεθεί.

  • Αν καθορισμένα IDs αναφέρονται, όπως στο "ids": ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"], μόνο αυτές οι εφαρμογές μπορούν να συνδεθούν.

  • Αν καθοριστούν matches, αυτές οι διαδικτυακές εφαρμογές θα μπορούν να συνδεθούν:

"matches": [
"https://*.google.com/*",
"*://*.chromium.org/*",
  • Αν έχει καθοριστεί ως κενό: "externally_connectable": {}, καμία εφαρμογή ή ιστότοπος δεν θα μπορεί να συνδεθεί.

Όσο λιγότερες επεκτάσεις και διευθύνσεις URL αναφέρονται εδώ, τόσο μικρότερη θα είναι η επιφάνεια επίθεσης.

Αν μια ιστοσελίδα ευάλωτη σε XSS ή takeover αναφέρεται σε externally_connectable, ένας επιτιθέμενος θα μπορεί να στείλει μηνύματα απευθείας στο background script, παρακάμπτοντας εντελώς το Content Script και το CSP του.

Επομένως, αυτό είναι μια πολύ ισχυρή παράκαμψη.

Επιπλέον, αν ο πελάτης εγκαταστήσει μια κακόβουλη επέκταση, ακόμη και αν δεν επιτρέπεται να επικοινωνήσει με την ευάλωτη επέκταση, θα μπορούσε να εισάγει δεδομένα XSS σε μια επιτρεπόμενη ιστοσελίδα ή να καταχραστεί τις APIs WebRequest ή DeclarativeNetRequest για να χειριστεί αιτήματα σε έναν στοχευμένο τομέα, αλλάζοντας το αίτημα μιας σελίδας για ένα αρχείο JavaScript. (Σημειώστε ότι το CSP στη στοχευμένη σελίδα θα μπορούσε να αποτρέψει αυτές τις επιθέσεις). Αυτή η ιδέα προέρχεται από αυτή τη γραφή.

Περίληψη επικοινωνίας

Επέκταση <--> WebApp

Για να επικοινωνήσουν το περιεχόμενο script και η ιστοσελίδα, συνήθως χρησιμοποιούνται μηνύματα post. Επομένως, στην εφαρμογή ιστού θα βρείτε συνήθως κλήσεις στη συνάρτηση window.postMessage και στο περιεχόμενο script ακροατές όπως window.addEventListener. Σημειώστε ωστόσο ότι η επέκταση θα μπορούσε επίσης να επικοινωνήσει με την εφαρμογή ιστού στέλνοντας ένα Post Message (και επομένως η ιστοσελίδα θα πρέπει να το περιμένει) ή απλώς να κάνει την ιστοσελίδα να φορτώσει ένα νέο script.

Μέσα στην επέκταση

Συνήθως η συνάρτηση chrome.runtime.sendMessage χρησιμοποιείται για να στείλει ένα μήνυμα μέσα στην επέκταση (συνήθως διαχειρίζεται από το background script) και για να το λάβει και να το διαχειριστεί δηλώνεται ένας ακροατής καλώντας chrome.runtime.onMessage.addListener.

Είναι επίσης δυνατό να χρησιμοποιηθεί chrome.runtime.connect() για να υπάρχει μια μόνιμη σύνδεση αντί να στέλνονται μεμονωμένα μηνύματα, είναι δυνατό να χρησιμοποιηθεί για να στείλει και λάβει μηνύματα όπως στο παρακάτω παράδειγμα:

chrome.runtime.connect() παράδειγμα

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

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

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

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

</details>

Είναι επίσης δυνατό να στείλετε μηνύματα από ένα background script σε ένα content script που βρίσκεται σε μια συγκεκριμένη καρτέλα καλώντας **`chrome.tabs.sendMessage`** όπου θα χρειαστεί να υποδείξετε το **ID της καρτέλας** στην οποία θα στείλετε το μήνυμα.

### Από επιτρεπόμενο `externally_connectable` στην επέκταση

**Web εφαρμογές και εξωτερικές επεκτάσεις προγράμματος περιήγησης που επιτρέπονται** στη ρύθμιση `externally_connectable` μπορούν να στέλνουν αιτήματα χρησιμοποιώντας :
```javascript
chrome.runtime.sendMessage(extensionId, ...

Όπου είναι απαραίτητο να αναφερθεί το extension ID.

Native Messaging

Είναι δυνατόν οι background scripts να επικοινωνούν με binaries μέσα στο σύστημα, τα οποία μπορεί να είναι ευάλωτα σε κρίσιμες ευπάθειες όπως RCEs αν αυτή η επικοινωνία δεν είναι σωστά ασφαλισμένη. Περισσότερα σχετικά με αυτό αργότερα.

chrome.runtime.sendNativeMessage(
'com.my_company.my_application',
{text: 'Hello'},
function (response) {
console.log('Received ' + response);
}
);

Web ↔︎ Επικοινωνία Σκηνών Περιεχομένου

Τα περιβάλλοντα όπου λειτουργούν οι σκηνές περιεχομένου και όπου υπάρχουν οι σελίδες φιλοξενίας είναι χωρισμένα το ένα από το άλλο, εξασφαλίζοντας απομόνωση. Παρά αυτή την απομόνωση, και τα δύο έχουν τη δυνατότητα να αλληλεπιδρούν με το Document Object Model (DOM) της σελίδας, μια κοινή πηγή. Για να συμμετάσχει η σελίδα φιλοξενίας στην επικοινωνία με τη σκηνή περιεχομένου, ή έμμεσα με την επέκταση μέσω της σκηνής περιεχομένου, απαιτείται να χρησιμοποιήσει το DOM που είναι προσβάσιμο και από τις δύο πλευρές ως κανάλι επικοινωνίας.

Μηνύματα Post

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

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

if (event.data.type && (event.data.type === "FROM_PAGE")) {
console.log("Content script received: " + event.data.text);
// Forward the message to the background script
port.postMessage(event.data.text);
}
}, false);
example.js
document.getElementById("theButton").addEventListener("click", () => {
window.postMessage(
{type : "FROM_PAGE", text : "Hello from the webpage!"}, "*");
}, false);

Μια ασφαλής επικοινωνία Post Message θα πρέπει να ελέγχει την αυθεντικότητα του ληφθέντος μηνύματος, αυτό μπορεί να γίνει ελέγχοντας:

  • event.isTrusted: Αυτό είναι True μόνο αν το γεγονός προκλήθηκε από ενέργεια του χρήστη

  • Το περιεχόμενο του script μπορεί να περιμένει ένα μήνυμα μόνο αν ο χρήστης εκτελέσει κάποια ενέργεια

  • origin domain: μπορεί να περιμένει ένα μήνυμα μόνο από μια λίστα επιτρεπόμενων τομέων.

  • Αν χρησιμοποιηθεί regex, να είστε πολύ προσεκτικοί

  • Source: received_message.source !== window μπορεί να χρησιμοποιηθεί για να ελέγξει αν το μήνυμα ήταν από το ίδιο παράθυρο όπου το Content Script ακούει.

Οι προηγούμενοι έλεγχοι, ακόμα και αν εκτελούνται, θα μπορούσαν να είναι ευάλωτοι, οπότε ελέγξτε στην επόμενη σελίδα πιθανά bypasses Post Message:

Iframe

Ένας άλλος πιθανός τρόπος επικοινωνίας μπορεί να είναι μέσω Iframe URLs, μπορείτε να βρείτε ένα παράδειγμα σε:

DOM

Αυτό δεν είναι "ακριβώς" ένας τρόπος επικοινωνίας, αλλά το web και το content script θα έχουν πρόσβαση στο web DOM. Έτσι, αν το content script διαβάζει κάποιες πληροφορίες από αυτό, ** εμπιστευόμενο το web DOM**, το web θα μπορούσε να τροποποιήσει αυτά τα δεδομένα (επειδή το web δεν θα πρέπει να εμπιστεύεται, ή επειδή το web είναι ευάλωτο σε XSS) και να συμβιβάσει το Content Script.

Μπορείτε επίσης να βρείτε ένα παράδειγμα ενός DOM based XSS για να συμβιβάσετε μια επέκταση προγράμματος περιήγησης σε:

Επικοινωνία Content Script ↔︎ Background Script

Ένα Content Script μπορεί να χρησιμοποιήσει τις συναρτήσεις runtime.sendMessage() ή tabs.sendMessage() για να στείλει ένα μοναδικό JSON-serializable μήνυμα.

Για να χειριστείτε την απάντηση, χρησιμοποιήστε την επιστρεφόμενη Promise. Αν και, για λόγους συμβατότητας, μπορείτε ακόμα να περάσετε μια callback ως τελευταίο επιχείρημα.

Η αποστολή ενός αιτήματος από ένα content script φαίνεται έτσι:

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

Αποστολή αιτήματος από την επέκταση (συνήθως ένα 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 listener γεγονότων για να χειριστείτε το μήνυμα. Αυτό φαίνεται το ίδιο από ένα περιεχόμενο script ή μια σελίδα επέκτασης.

// 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. Όσον αφορά τη χρήση callbacks, η συνάρτηση sendResponse() θεωρείται έγκυρη μόνο εάν εκτελείται άμεσα μέσα στο συγχρονισμένο πλαίσιο ή εάν ο χειριστής γεγονότος υποδεικνύει μια ασύγχρονη λειτουργία επιστρέφοντας true. Εάν κανένας από τους χειριστές δεν επιστρέψει true ή εάν η συνάρτηση sendResponse() αφαιρεθεί από τη μνήμη (garbage-collected), το callback που σχετίζεται με τη συνάρτηση sendMessage() θα ενεργοποιηθεί από προεπιλογή.

Native Messaging

Οι επεκτάσεις προγράμματος περιήγησης επιτρέπουν επίσης την επικοινωνία με δυαδικά αρχεία στο σύστημα μέσω 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 είναι η συμβολοσειρά που μεταβιβάζεται στο runtime.connectNative() ή runtime.sendNativeMessage() για να επικοινωνήσει με την εφαρμογή από τα background scripts της επέκτασης του προγράμματος περιήγησης. Το path είναι η διαδρομή προς το δυαδικό αρχείο, υπάρχει μόνο 1 έγκυρος type που είναι το stdio (χρησιμοποιήστε stdin και stdout) και οι allowed_origins υποδεικνύουν τις επεκτάσεις που μπορούν να έχουν πρόσβαση σε αυτό (και δεν μπορούν να έχουν wildcard).

Το Chrome/Chromium θα αναζητήσει αυτό το json σε κάποια μητρώα των Windows και σε κάποιες διαδρομές σε macOS και Linux (περισσότερες πληροφορίες στα docs).

Η επέκταση του προγράμματος περιήγησης χρειάζεται επίσης την άδεια nativeMessaing δηλωμένη για να μπορεί να χρησιμοποιήσει αυτή την επικοινωνία.

Αυτή είναι η εμφάνιση κάποιου κώδικα background script που στέλνει μηνύματα σε μια εγγενή εφαρμογή:

chrome.runtime.sendNativeMessage(
'com.my_company.my_application',
{text: 'Hello'},
function (response) {
console.log('Received ' + response);
}
);

In αυτή την ανάρτηση στο blog, προτείνεται ένα ευάλωτο μοτίβο που εκμεταλλεύεται τα εγγενή μηνύματα:

  1. Η επέκταση του προγράμματος περιήγησης έχει ένα μοτίβο wildcard για το περιεχόμενο του script.

  2. Το περιεχόμενο του script περνάει μηνύματα postMessage στο background script χρησιμοποιώντας sendMessage.

  3. Το background script περνάει το μήνυμα στην εγγενή εφαρμογή χρησιμοποιώντας sendNativeMessage.

  4. Η εγγενής εφαρμογή χειρίζεται το μήνυμα επικίνδυνα, οδηγώντας σε εκτέλεση κώδικα.

Και μέσα σε αυτό εξηγείται ένα παράδειγμα μετάβασης από οποιαδήποτε σελίδα σε RCE εκμεταλλευόμενο μια επέκταση προγράμματος περιήγησης.

Ευαίσθητες Πληροφορίες στη Μνήμη/Κώδικα/Πρόχειρο

Εάν μια Επέκταση Προγράμματος Περιήγησης αποθηκεύει ευαίσθητες πληροφορίες μέσα στη μνήμη της, αυτές θα μπορούσαν να εκχυθούν (ειδικά σε μηχανές Windows) και να αναζητηθούν για αυτές τις πληροφορίες.

Επομένως, η μνήμη της Επέκτασης Προγράμματος Περιήγησης δεν θα πρέπει να θεωρείται ασφαλής και ευαίσθητες πληροφορίες όπως διαπιστευτήρια ή μνημονικές φράσεις δεν θα πρέπει να αποθηκεύονται.

Φυσικά, μην βάζετε ευαίσθητες πληροφορίες στον κώδικα, καθώς θα είναι δημόσιες.

Για να εκχυθεί η μνήμη από τον περιηγητή μπορείτε να εκχύσετε τη μνήμη της διαδικασίας ή να πάτε στις ρυθμίσεις της επέκτασης του προγράμματος περιήγησης κάνοντας κλικ στο Inspect pop-up -> Στην ενότητα Memory -> Take a snapshot και CTRL+F για να αναζητήσετε μέσα στο στιγμιότυπο ευαίσθητες πληροφορίες.

Επιπλέον, οι πολύ ευαίσθητες πληροφορίες όπως μνημονικά κλειδιά ή κωδικοί πρόσβασης δεν θα πρέπει να επιτρέπεται να αντιγράφονται στο πρόχειρο (ή τουλάχιστον να αφαιρούνται από το πρόχειρο σε λίγα δευτερόλεπτα) γιατί τότε οι διαδικασίες που παρακολουθούν το πρόχειρο θα μπορούν να τις αποκτήσουν.

Φόρτωση μιας Επέκτασης στον Περιηγητή

  1. Κατεβάστε την Επέκταση Προγράμματος Περιήγησης & αποσυμπιέστε την

  2. Πηγαίνετε στο chrome://extensions/ και ενεργοποιήστε τη Λειτουργία Προγραμματιστή

  3. Κάντε κλικ στο κουμπί Φόρτωση αποσυμπιεσμένου

Στο Firefox πηγαίνετε στο about:debugging#/runtime/this-firefox και κάντε κλικ στο κουμπί Φόρτωση προσωρινής προσθήκης.

Λήψη του πηγαίου κώδικα από το κατάστημα

Ο πηγαίος κώδικας μιας επέκτασης Chrome μπορεί να αποκτηθεί μέσω διαφόρων μεθόδων. Παρακάτω παρατίθενται λεπτομερείς εξηγήσεις και οδηγίες για κάθε επιλογή.

Λήψη Επέκτασης ως ZIP μέσω Γραμμής Εντολών

Ο πηγαίος κώδικας μιας επέκτασης Chrome μπορεί να ληφθεί ως αρχείο ZIP χρησιμοποιώντας τη γραμμή εντολών. Αυτό περιλαμβάνει τη χρήση του curl για να αποκτήσετε το αρχείο ZIP από μια συγκεκριμένη διεύθυνση URL και στη συνέχεια την εξαγωγή των περιεχομένων του αρχείου ZIP σε έναν φάκελο. Ακολουθούν τα βήματα:

  1. Αντικαταστήστε το "extension_id" με το πραγματικό ID της επέκτασης.

  2. Εκτελέστε τις παρακάτω εντολές:

extension_id=your_extension_id   # Replace with the actual extension ID
curl -L -o "$extension_id.zip" "https://clients2.google.com/service/update2/crx?response=redirect&os=mac&arch=x86-64&nacl_arch=x86-64&prod=chromecrx&prodchannel=stable&prodversion=44.0.2403.130&x=id%3D$extension_id%26uc"
unzip -d "$extension_id-source" "$extension_id.zip"

Χρησιμοποιήστε την ιστοσελίδα CRX Viewer

https://robwu.nl/crxviewer/

Χρησιμοποιήστε την επέκταση CRX Viewer

Μια άλλη βολική μέθοδος είναι η χρήση του Chrome Extension Source Viewer, το οποίο είναι ένα ανοιχτού κώδικα έργο. Μπορεί να εγκατασταθεί από το Chrome Web Store. Ο πηγαίος κώδικας του viewer είναι διαθέσιμος στο GitHub repository.

Δείτε τον πηγαίο κώδικα της τοπικά εγκατεστημένης επέκτασης

Οι επεκτάσεις Chrome που έχουν εγκατασταθεί τοπικά μπορούν επίσης να επιθεωρηθούν. Να πώς:

  1. Αποκτήστε πρόσβαση στον τοπικό φάκελο προφίλ του Chrome επισκεπτόμενοι το chrome://version/ και εντοπίζοντας το πεδίο "Profile Path".

  2. Μεταβείτε στον υποφάκελο Extensions/ εντός του φακέλου προφίλ.

  3. Αυτός ο φάκελος περιέχει όλες τις εγκατεστημένες επεκτάσεις, συνήθως με τον πηγαίο κώδικα τους σε αναγνώσιμη μορφή.

Για να προσδιορίσετε τις επεκτάσεις, μπορείτε να αντιστοιχίσετε τα IDs τους με ονόματα:

  • Ενεργοποιήστε τη Λειτουργία Προγραμματιστή στη σελίδα about:extensions για να δείτε τα IDs κάθε επέκτασης.

  • Μέσα στον φάκελο κάθε επέκτασης, το αρχείο manifest.json περιέχει ένα αναγνώσιμο πεδίο name, βοηθώντας σας να προσδιορίσετε την επέκταση.

Χρησιμοποιήστε ένα Αρχειοθέτη ή Αποσυμπιεστή

Μεταβείτε στο Chrome Web Store και κατεβάστε την επέκταση. Το αρχείο θα έχει κατάληξη .crx. Αλλάξτε την κατάληξη του αρχείου από .crx σε .zip. Χρησιμοποιήστε οποιονδήποτε αρχειοθέτη (όπως WinRAR, 7-Zip, κ.λπ.) για να εξαγάγετε τα περιεχόμενα του αρχείου ZIP.

Χρησιμοποιήστε τη Λειτουργία Προγραμματιστή στο Chrome

Ανοίξτε το Chrome και μεταβείτε στο chrome://extensions/. Ενεργοποιήστε τη "Λειτουργία προγραμματιστή" στην επάνω δεξιά γωνία. Κάντε κλικ στο "Φόρτωση αποσυμπιεσμένης επέκτασης...". Μεταβείτε στον φάκελο της επέκτασής σας. Αυτό δεν κατεβάζει τον πηγαίο κώδικα, αλλά είναι χρήσιμο για την προβολή και την τροποποίηση του κώδικα μιας ήδη κατεβασμένης ή αναπτυγμένης επέκτασης.

Σύνολο δεδομένων manifest επεκτάσεων Chrome

Για να προσπαθήσετε να εντοπίσετε ευάλωτες επεκτάσεις προγράμματος περιήγησης, μπορείτε να χρησιμοποιήσετε το https://github.com/palant/chrome-extension-manifests-dataset και να ελέγξετε τα αρχεία manifest τους για πιθανά ευάλωτα σημάδια. Για παράδειγμα, για να ελέγξετε για επεκτάσεις με περισσότερους από 25000 χρήστες, content_scripts και την άδεια nativeMessaging:

# 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')"

Λίστα Ελέγχου Ασφαλείας

Ακόμα και αν οι Επεκτάσεις Περιηγητή έχουν μια περιορισμένη επιφάνεια επίθεσης, μερικές από αυτές μπορεί να περιέχουν ευπάθειες ή πιθανές βελτιώσεις ενίσχυσης. Οι παρακάτω είναι οι πιο κοινές: