Μεθοδολογία Pentesting για Επεκτάσεις Browser
Tip
Μάθετε & εξασκηθείτε στο AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Μάθετε & εξασκηθείτε στο Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Υποστηρίξτε το HackTricks
- Ελέγξτε τα σχέδια συνδρομής!
- Εγγραφείτε στην 💬 ομάδα Discord ή στην ομάδα telegram ή ακολουθήστε μας στο Twitter 🐦 @hacktricks_live.
- Μοιραστείτε κόλπα hacking υποβάλλοντας PRs στα HackTricks και HackTricks Cloud github repos.
Βασικές Πληροφορίες
Οι επεκτάσεις προγράμματος περιήγησης γράφονται σε JavaScript και φορτώνονται από το πρόγραμμα περιήγησης στο παρασκήνιο. Έχουν το DOM αλλά μπορούν να αλληλεπιδράσουν με τα DOM άλλων ιστότοπων. Αυτό σημαίνει ότι μπορεί να θέσουν σε κίνδυνο την εμπιστευτικότητα, ακεραιότητα και διαθεσιμότητα άλλων ιστότοπων (CIA).
Κύρια Συστατικά
Η δομή των επεκτάσεων αποδίδεται καλύτερα οπτικά και αποτελείται από τρία συστατικά. Ας δούμε κάθε συστατικό πιο αναλυτικά.
 (1) (1).png)
Content Scripts
Κάθε content script έχει άμεση πρόσβαση στο DOM μιας μοναδικής ιστοσελίδας και έτσι εκτίθεται σε πιθανώς κακόβουλα δεδομένα. Ωστόσο, το content script δεν περιέχει δικαιώματα πέραν της ικανότητας αποστολής μηνυμάτων στον extension core.
Extension Core
Ο extension core περιέχει τα περισσότερα προνόμια/πρόσβασης της επέκτασης, αλλά ο extension core μπορεί να αλληλεπιδρά με web περιεχόμενο μόνο μέσω του XMLHttpRequest και των content scripts. Επίσης, ο extension core δεν έχει άμεση πρόσβαση στο host machine.
Native Binary
Η επέκταση επιτρέπει ένα native binary που μπορεί να προσπελάσει το host machine με τα πλήρη προνόμια του χρήστη. Το native binary αλληλεπιδρά με τον extension core μέσω του standard Netscape Plugin Application Programming Interface (NPAPI) που χρησιμοποιήθηκε από το Flash και άλλα browser plug-ins.
Όρια
Caution
Για να αποκτήσει τα πλήρη προνόμια του χρήστη, ένας επιτιθέμενος πρέπει να πείσει την επέκταση να προωθήσει κακόβουλα δεδομένα από το content script στον extension core και από τον extension core στο native binary.
Κάθε συστατικό της επέκτασης είναι διαχωρισμένο από τα άλλα με ισχυρά προστατευτικά όρια. Κάθε συστατικό τρέχει σε μια ξεχωριστή διεργασία του λειτουργικού συστήματος. Τα Content scripts και οι extension cores τρέχουν σε sandbox processes που δεν είναι διαθέσιμες στις περισσότερες υπηρεσίες του λειτουργικού συστήματος.
Επιπλέον, τα content scripts διαχωρίζονται από τις σχετιζόμενες ιστοσελίδες τους εκτελούμενα σε ξεχωριστό JavaScript heap. Το content script και η ιστοσελίδα έχουν πρόσβαση στο ίδιο υποκείμενο DOM, αλλά οι δύο ποτέ δεν ανταλλάσσουν JavaScript pointers, εμποδίζοντας το leaking της JavaScript λειτουργικότητας.
manifest.json
Μια επέκταση Chrome είναι απλώς ένας φάκελος ZIP με κατάληξη αρχείου .crx file extension. Ο πυρήνας της επέκτασης είναι το manifest.json αρχείο στη ρίζα του φακέλου, που καθορίζει τη διάταξη, τα δικαιώματα και άλλες επιλογές ρύθμισης.
Παράδειγμα:
{
"manifest_version": 2,
"name": "My extension",
"version": "1.0",
"permissions": ["storage"],
"content_scripts": [
{
"js": ["script.js"],
"matches": ["https://example.com/*", "https://www.example.com/*"],
"exclude_matches": ["*://*/*business*"]
}
],
"background": {
"scripts": ["background.js"]
},
"options_ui": {
"page": "options.html"
}
}
content_scripts
Τα content scripts φορτώνονται κάθε φορά που ο χρήστης πλοηγείται σε μια σελίδα που ταιριάζει, στην περίπτωσή μας οποιαδήποτε σελίδα που ταιριάζει με την έκφραση https://example.com/* και δεν ταιριάζει με το regex *://*/*/business*. Εκτελούνται όπως τα ίδια τα scripts της σελίδας και έχουν πλήρη πρόσβαση στο Document Object Model (DOM).
"content_scripts": [
{
"js": [
"script.js"
],
"matches": [
"https://example.com/*",
"https://www.example.com/*"
],
"exclude_matches": ["*://*/*business*"],
}
],
Για να συμπεριλάβετε ή να εξαιρέσετε περισσότερα URLs, μπορείτε επίσης να χρησιμοποιήσετε τα include_globs και exclude_globs.
Παρακάτω είναι ένα παράδειγμα content script που θα προσθέσει ένα explain button στη σελίδα και θα χρησιμοποιήσει the storage API για να ανακτήσει την τιμή message από το extension’s storage.
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)
Ένα μήνυμα αποστέλλεται στις extension pages από το content script όταν πατηθεί αυτό το κουμπί, μέσω της χρήσης του runtime.sendMessage() API. Αυτό οφείλεται στον περιορισμό του content script στην άμεση πρόσβαση σε APIs, με το storage να αποτελεί μία από τις λίγες εξαιρέσεις. Για λειτουργίες πέρα από αυτές τις εξαιρέσεις, τα μηνύματα αποστέλλονται σε extension pages με τα οποία τα content scripts μπορούν να επικοινωνήσουν.
Warning
Ανάλογα με τον browser, οι δυνατότητες του content script μπορεί να διαφέρουν ελαφρώς. Για Chromium-based browsers, η λίστα δυνατοτήτων είναι διαθέσιμη στην Chrome Developers documentation, και για Firefox, το MDN αποτελεί την κύρια πηγή.
Αξίζει επίσης να σημειωθεί ότι τα content scripts μπορούν να επικοινωνήσουν με background scripts, επιτρέποντάς τους να εκτελούν ενέργειες και να επιστρέφουν απαντήσεις.
Για να δείτε και να αποσφαλματώσετε content scripts στο Chrome, το μενού Chrome developer tools είναι προσβάσιμο από Options > More tools > Developer tools Ή πατώντας Ctrl + Shift + I.
Μόλις εμφανιστούν τα developer tools, κάντε κλικ στην Source tab, και στη συνέχεια στην Content Scripts tab. Αυτό επιτρέπει την παρακολούθηση των running content scripts από διάφορα extensions και τη ρύθμιση breakpoints για να παρακολουθείτε τη ροή εκτέλεσης.
Εγχυόμενα content scripts
Tip
Σημειώστε ότι Content Scripts aren’t mandatory, καθώς είναι επίσης δυνατό να dynamically inject scripts και να programatically inject them σε σελίδες web μέσω του
tabs.executeScript. Αυτό παρέχει στην πραγματικότητα πιο granular controls.
Για την programmatic injection ενός content script, το extension απαιτεί να έχει host permissions για τη σελίδα στην οποία θα εγχυθούν τα scripts. Αυτά τα permissions μπορούν να αποκτηθούν είτε με requesting them μέσα στο manifest του extension είτε προσωρινά μέσω του activeTab.
Παράδειγμα extension βασισμένης στο activeTab
{
"name": "My extension",
...
"permissions": [
"activeTab",
"scripting"
],
"background": {
"service_worker": "background.js"
},
"action": {
"default_title": "Action Button"
}
}
- Εισαγωγή ενός αρχείου JS με κλικ:
// content-script.js
document.body.style.backgroundColor = "orange"
//service-worker.js - Inject the JS file
chrome.action.onClicked.addListener((tab) => {
chrome.scripting.executeScript({
target: { tabId: tab.id },
files: ["content-script.js"],
})
})
- Inject a function με κλικ:
//service-worker.js - Inject a function
function injectedFunction() {
document.body.style.backgroundColor = "orange"
}
chrome.action.onClicked.addListener((tab) => {
chrome.scripting.executeScript({
target: { tabId: tab.id },
func: injectedFunction,
})
})
Παράδειγμα με δικαιώματα 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" })
Για να συμπεριλάβετε ή να εξαιρέσετε περισσότερα URLs, είναι επίσης δυνατό να χρησιμοποιήσετε include_globs και exclude_globs.
Σενάρια περιεχομένου run_at
Το πεδίο run_at ελέγχει πότε τα αρχεία JavaScript εισάγονται στη σελίδα web. Η προτιμώμενη και προεπιλεγμένη τιμή είναι "document_idle".
Οι δυνατές τιμές είναι:
document_idle: Όποτε είναι δυνατόνdocument_start: Μετά από οποιαδήποτε αρχεία απόcss, αλλά πριν κατασκευαστεί οποιοδήποτε άλλο DOM ή εκτελεστεί οποιοδήποτε άλλο script.document_end: Αμέσως μετά την ολοκλήρωση του DOM, αλλά πριν φορτωθούν υπο-πόροι όπως images και frames.
Μέσω 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
Τα μηνύματα που αποστέλλονται από content scripts λαμβάνονται από την background page, η οποία λειτουργεί ως κεντρικός κόμβος στον συντονισμό των συστατικών της επέκτασης. Σημειωτέον, η background page παραμένει ενεργή καθ’ όλη τη διάρκεια ζωής της επέκτασης, λειτουργώντας διακριτικά χωρίς άμεση αλληλεπίδραση με τον χρήστη. Διαθέτει το δικό της Document Object Model (DOM), επιτρέποντας πολύπλοκες αλληλεπιδράσεις και διαχείριση κατάστασης.
Κύρια σημεία:
- Ρόλος της background page: Λειτουργεί ως το νευρικό κέντρο της επέκτασης, εξασφαλίζοντας επικοινωνία και συντονισμό μεταξύ των διαφόρων τμημάτων της επέκτασης.
- Μόνιμη παρουσία: Είναι μια συνεχώς παρούσα οντότητα, αόρατη για τον χρήστη αλλά ουσιώδης για τη λειτουργικότητα της επέκτασης.
- Αυτόματη δημιουργία: Αν δεν οριστεί ρητά, ο browser θα δημιουργήσει αυτόματα μια background page. Αυτή η αυτόματα δημιουργούμενη σελίδα θα περιλαμβάνει όλα τα background scripts που καθορίζονται στο manifest της επέκτασης, εξασφαλίζοντας την απρόσκοπτη λειτουργία των background tasks της επέκτασης.
Tip
Η ευκολία που παρέχει ο browser με την αυτόματη δημιουργία μιας background page (όταν δεν δηλώνεται ρητά) διασφαλίζει ότι όλα τα αναγκαία background scripts είναι ενσωματωμένα και λειτουργικά, απλοποιώντας τη διαδικασία εγκατάστασης της επέκτασης.
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.
Για debugging του background script μπορείτε να μεταβείτε στις extension details και να inspect το service worker, αυτό θα ανοίξει τα developer tools με το background script:
Options pages and other
Οι browser extensions μπορούν να περιέχουν διάφορους τύπους σελίδων:
- Action pages εμφανίζονται σε ένα drop-down όταν το εικονίδιο της επέκτασης πατηθεί.
- Σελίδες που η επέκταση θα φορτώνει σε νέα καρτέλα.
- Option Pages: Αυτή η σελίδα εμφανίζεται πάνω από την επέκταση όταν πατηθεί. Στο προηγούμενο manifest στην περίπτωσή μου κατάφερα να έχω πρόσβαση σε αυτή τη σελίδα στο
chrome://extensions/?options=fadlhnelkbeojnebcbkacjilhnbjfjcaή κάνοντας κλικ:
.png)
Σημειώστε ότι αυτές οι σελίδες δεν είναι επίμονες όπως οι background pages, καθώς φορτώνουν δυναμικά περιεχόμενο όταν χρειάζεται. Παρ’ όλα αυτά, μοιράζονται ορισμένες δυνατότητες με το background page:
- Communication with Content Scripts: Όπως το background page, αυτές οι σελίδες μπορούν να λαμβάνουν μηνύματα από content scripts, διευκολύνοντας την αλληλεπίδραση εντός της επέκτασης.
- Access to Extension-Specific APIs: Αυτές οι σελίδες έχουν πλήρη πρόσβαση σε extension-specific APIs, υπό τις άδειες (permissions) που έχουν οριστεί για την επέκταση.
permissions & host_permissions
permissions και host_permissions είναι πεδία στο manifest.json που δείχνουν ποιες άδειες έχει η επέκταση του browser (storage, location…) και σε ποιες ιστοσελίδες.
Καθώς οι browser extensions μπορούν να είναι ιδιαίτερα privileged, μια κακόβουλη ή παραβιασμένη επέκταση μπορεί να επιτρέψει στον επιτιθέμενο διάφορα μέσα για να κλέψει ευαίσθητες πληροφορίες και να κατασκοπεύσει τον χρήστη.
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 και πιθανές παρακάμψεις δείτε:
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 is accesible:
.png)
Although, if the manifest.json parameter use_dynamic_url is used, this id can be dynamic.
Tip
Σημειώστε ότι ακόμη κι αν μια σελίδα αναφέρεται εδώ, μπορεί να είναι protected against ClickJacking χάρη στην Content Security Policy. Επομένως πρέπει επίσης να την ελέγξετε (τμήμα frame-ancestors) προτού επιβεβαιώσετε ότι μια επίθεση ClickJacking είναι δυνατή.
Being allowed to access these pages make these pages potentially vulnerable ClickJacking:
Tip
Το να επιτρέπεται να φορτώνονται αυτές οι σελίδες μόνο από την extension και όχι από τυχαία URLs μπορεί να αποτρέψει επιθέσεις ClickJacking.
Caution
Σημειώστε ότι οι σελίδες από
web_accessible_resourcesκαι άλλες σελίδες της extension είναι επίσης ικανές να contacting background scripts. Έτσι, αν κάποια από αυτές τις σελίδες είναι ευάλωτη σε XSS, μπορεί να ανοίξει μεγαλύτερη ευπάθεια.Επιπλέον, σημειώστε ότι μπορείτε να ανοίξετε μόνο τις σελίδες που δηλώνονται στο
web_accessible_resourcesμέσα σε iframes, αλλά από ένα new tab είναι δυνατό να αποκτήσετε πρόσβαση σε οποιαδήποτε σελίδα της extension γνωρίζοντας το extension ID. Επομένως, αν βρεθεί XSS που εκμεταλλεύεται τις ίδιες παραμέτρους, θα μπορούσε να εκμεταλλευτείται ακόμη και αν η σελίδα δεν είναι ρυθμισμένη στοweb_accessible_resources.
externally_connectable
A per the docs, The "externally_connectable" manifest property declares which extensions and web pages can connect to your extension via runtime.connect and runtime.sendMessage.
- If the
externally_connectablekey is not declared in your extension’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/*",
- Εάν δηλωθεί ως κενό:
"externally_connectable": {}, καμία app ή web δεν θα μπορεί να συνδεθεί.
Όσο λιγότερες επεκτάσεις και URLs δηλώνονται εδώ, τόσο μικρότερη θα είναι η attack surface.
Caution
Εάν μια σελίδα web που είναι ευάλωτη σε XSS ή takeover δηλωθεί στο
externally_connectable, ένας attacker θα μπορεί να στέλνει μηνύματα απευθείας στο background script, παρακάμπτοντας πλήρως το Content Script και το CSP.Επομένως, αυτό είναι ένα πολύ ισχυρό bypass.
Επιπλέον, εάν ο client εγκαταστήσει μια rouge extension, ακόμη κι αν δεν επιτρέπεται να επικοινωνεί με την ευάλωτη extension, αυτή θα μπορούσε να εισάγει XSS data σε μια επιτρεπόμενη web σελίδα ή να καταχραστεί τα APIs WebRequest ή DeclarativeNetRequest για να χειριστεί requests σε έναν στοχοθετημένο domain, τροποποιώντας το request μιας σελίδας για ένα JavaScript file. (Σημειώστε ότι το CSP στην στοχοθετημένη σελίδα θα μπορούσε να αποτρέψει αυτές τις επιθέσεις). Αυτή η ιδέα προέρχεται from this writeup.
Περίληψη επικοινωνίας
Επέκταση <–> WebApp
Για να επικοινωνήσουν το Content Script και η σελίδα web συνήθως χρησιμοποιούνται post messages. Επομένως, στην web application θα βρείτε συνήθως κλήσεις στη λειτουργία window.postMessage και στο Content Script listeners όπως window.addEventListener. Σημειώστε ωστόσο ότι η επέκταση θα μπορούσε επίσης να επικοινωνήσει με την web application στέλνοντας ένα Post Message (και επομένως η web πρέπει να το αναμένει) ή απλώς να κάνει την web να φορτώσει ένα νέο script.
Μέσα στην επέκταση
Συνήθως η λειτουργία chrome.runtime.sendMessage χρησιμοποιείται για να στείλει ένα μήνυμα εντός της επέκτασης (συνήθως διαχειρίζεται από το background script) και για να το λάβει και να το χειριστεί δηλώνεται ένας listener καλώντας 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 που βρίσκεται σε μια συγκεκριμένη καρτέλα (tab) καλώντας **`chrome.tabs.sendMessage`**, όπου θα χρειαστεί να υποδείξετε το **ID της καρτέλας** στην οποία θα σταλεί το μήνυμα.
### Από επιτρεπόμενα `externally_connectable` προς την επέκταση
**Web apps και εξωτερικές browser extensions που έχουν επιτραπεί** στη ρύθμιση `externally_connectable` μπορούν να στείλουν αιτήματα χρησιμοποιώντας :
```javascript
chrome.runtime.sendMessage(extensionId, ...
Όπου χρειάζεται να αναφερθεί το extension ID.
Native Messaging
Είναι δυνατό για τα background scripts να επικοινωνούν με binaries στο σύστημα, κάτι που μπορεί να είναι επιρρεπές σε κρίσιμες ευπάθειες όπως RCEs εάν αυτή η επικοινωνία δεν προστατευτεί σωστά. More on this later.
chrome.runtime.sendNativeMessage(
"com.my_company.my_application",
{ text: "Hello" },
function (response) {
console.log("Received " + response)
}
)
Web ↔︎ Content Script Επικοινωνία
Τα περιβάλλοντα όπου εκτελούνται τα content scripts και όπου υπάρχουν οι host pages είναι διαχωρισμένα μεταξύ τους, εξασφαλίζοντας απομόνωση. Παρά αυτήν την απομόνωση, και τα δύο έχουν τη δυνατότητα να αλληλεπιδρούν με το Document Object Model (DOM) της σελίδας, έναν κοινό πόρο. Για να επικοινωνήσει η host page με το content script, ή έμμεσα με το extension μέσω του content script, απαιτείται η χρήση του DOM που είναι προσβάσιμο και από τα δύο μέρη ως κανάλι επικοινωνίας.
Post Messages
// This is like "chrome.runtime.sendMessage" but to maintain the connection
var port = chrome.runtime.connect()
window.addEventListener(
"message",
(event) => {
// We only accept messages from ourselves
if (event.source !== window) {
return
}
if (event.data.type && event.data.type === "FROM_PAGE") {
console.log("Content script received: " + event.data.text)
// Forward the message to the background script
port.postMessage(event.data.text)
}
},
false
)
document.getElementById("theButton").addEventListener(
"click",
() => {
window.postMessage(
{ type: "FROM_PAGE", text: "Hello from the webpage!" },
"*"
)
},
false
)
Μια ασφαλής Post Message επικοινωνία πρέπει να ελέγχει την αυθεντικότητα του ληφθέντος μηνύματος, αυτό μπορεί να γίνει ελέγχοντας:
event.isTrusted: Είναι True μόνο αν το event προκλήθηκε από ενέργεια του χρήστη- Το content script μπορεί να περιμένει μήνυμα μόνο αν ο χρήστης εκτελέσει κάποια ενέργεια
- origin domain: μπορεί να περιμένει μήνυμα μόνο από allowlist domains.
- Αν χρησιμοποιείται regex, να είστε πολύ προσεκτικοί
- Source:
received_message.source !== windowμπορεί να χρησιμοποιηθεί για να ελέγξει αν το μήνυμα ήταν από το ίδιο παράθυρο όπου το Content Script ακούει.
Οι προηγούμενοι έλεγχοι, ακόμη και αν εκτελεστούν, μπορεί να είναι ευάλωτοι, οπότε ελέγξτε στην παρακάτω σελίδα τους potential Post Message bypasses:
Iframe
Μια άλλη πιθανή μέθοδος επικοινωνίας μπορεί να είναι μέσω Iframe URLs, μπορείτε να βρείτε ένα παράδειγμα στο:
DOM
Αυτό δεν είναι “ακριβώς” ένας τρόπος επικοινωνίας, αλλά το web και το content script θα έχουν πρόσβαση στο web DOM. Έτσι, αν το content script διαβάζει πληροφορίες από αυτό και εμπιστεύεται το web DOM, το web θα μπορούσε να τροποποιήσει αυτά τα δεδομένα (επειδή το web δεν πρέπει να εμπιστεύεται, ή επειδή το web είναι ευάλωτο σε XSS) και να θέσει σε κίνδυνο το Content Script.
Μπορείτε επίσης να βρείτε ένα παράδειγμα DOM based XSS to compromise a browser extension στο:
Content Script ↔︎ Background Script Communication
A Content Script can use the functions runtime.sendMessage() or tabs.sendMessage() to send a one-time JSON-serializable message.
Για να χειριστείτε την απάντηση, χρησιμοποιήστε το επιστρεφόμενο 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)
})()
Αποστολή αιτήματος από το extension (συνήθως ένα background script). Παράδειγμα για το πώς να στείλετε μήνυμα στο content script στην επιλεγμένη καρτέλα:
// From https://stackoverflow.com/questions/36153999/how-to-send-a-message-between-chrome-extension-popup-and-content-script
;(async () => {
const [tab] = await chrome.tabs.query({
active: true,
lastFocusedWindow: true,
})
const response = await chrome.tabs.sendMessage(tab.id, { greeting: "hello" })
// do something with response here, not outside the function
console.log(response)
})()
Στην πλευρά του παραλήπτη, πρέπει να ρυθμίσετε έναν runtime.onMessage event listener ώστε να χειριστεί το μήνυμα. Αυτό φαίνεται το ίδιο τόσο από ένα content script όσο και από μια extension page.
// From https://stackoverflow.com/questions/70406787/javascript-send-message-from-content-js-to-background-js
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
console.log(
sender.tab
? "from a content script:" + sender.tab.url
: "from the extension"
)
if (request.greeting === "hello") sendResponse({ farewell: "goodbye" })
})
Στο παρατιθέμενο παράδειγμα, sendResponse() εκτελέστηκε με συγχρονικό τρόπο. Για να τροποποιήσετε τον onMessage event handler ώστε η εκτέλεση του sendResponse() να είναι ασύγχρονη, είναι απαραίτητο να συμπεριλάβετε return true;.
Ένα σημαντικό σημείο είναι ότι σε σενάρια όπου πολλαπλές σελίδες έχουν οριστεί να λαμβάνουν onMessage γεγονότα, η πρώτη σελίδα που θα εκτελέσει sendResponse() για ένα συγκεκριμένο γεγονός θα είναι η μόνη που θα μπορέσει να παραδώσει την απάντηση αποτελεσματικά. Οποιαδήποτε επόμενη απάντηση στο ίδιο γεγονός δεν θα ληφθεί υπόψη.
Κατά τη δημιουργία νέων extensions, προτιμήστε promises αντί για callbacks. Όσον αφορά τη χρήση callbacks, η συνάρτηση sendResponse() θεωρείται έγκυρη μόνο αν εκτελείται άμεσα μέσα στο συγχρονικό πλαίσιο, ή αν ο event handler δηλώνει ασύγχρονη λειτουργία επιστρέφοντας true. Αν κανένας από τους handlers δεν επιστρέψει true ή αν η sendResponse() διαγραφεί από τη μνήμη (garbage-collected), τότε η callback που σχετίζεται με τη sendMessage() θα καλείται από προεπιλογή.
Native Messaging
Οι browser extensions επιτρέπουν επίσης επικοινωνία με binaries στο σύστημα μέσω 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 είναι το string που περνάει σε runtime.connectNative() ή runtime.sendNativeMessage() για να επικοινωνήσει με την εφαρμογή από τα background scripts της επέκτασης του browser. Το path είναι το path προς το binary, υπάρχει μόνο 1 έγκυρος type που είναι stdio (χρησιμοποιεί stdin και stdout) και τα allowed_origins υποδεικνύουν τις επεκτάσεις που μπορούν να έχουν πρόσβαση (και δεν μπορούν να έχουν wildcard).
Chrome/Chromium θα ψάξει για αυτό το json σε ορισμένα Windows registry και σε κάποια paths σε macOS και Linux (περισσότερες πληροφορίες στα docs).
Tip
Η επέκταση του browser χρειάζεται επίσης την
nativeMessaingpermission δηλωμένη ώστε να μπορεί να χρησιμοποιήσει αυτή την επικοινωνία.
Έτσι φαίνεται κάποιο background script που στέλνει μηνύματα σε μια native εφαρμογή:
chrome.runtime.sendNativeMessage(
"com.my_company.my_application",
{ text: "Hello" },
function (response) {
console.log("Received " + response)
}
)
In this blog post, προτείνεται ένα ευάλωτο μοτίβο που καταχράται τα native messages:
- Η επέκταση προγράμματος περιήγησης έχει πρότυπο wildcard για το content script.
- Το content script προωθεί μηνύματα
postMessageστο background script χρησιμοποιώνταςsendMessage. - Το background script προωθεί το μήνυμα στην native εφαρμογή χρησιμοποιώντας
sendNativeMessage. - Η native εφαρμογή χειρίζεται το μήνυμα επικίνδυνα, οδηγώντας σε εκτέλεση κώδικα.
Και μέσα σε αυτό υπάρχει παράδειγμα που εξηγεί πώς από οποιαδήποτε σελίδα να επιτευχθεί RCE εκμεταλλευόμενοι μια browser extension.
Sensitive Information in Memory/Code/Clipboard
Εάν μια επέκταση προγράμματος περιήγησης αποθηκεύει ευαίσθητες πληροφορίες στη μνήμη της, αυτές μπορούν να εξαχθούν (ειδικά σε μηχανές Windows) και να αναζητηθούν για αυτές τις πληροφορίες.
Επομένως, η μνήμη της επέκτασης δεν πρέπει να θεωρείται ασφαλής και ευαίσθητες πληροφορίες όπως credentials ή mnemonic phrases δεν πρέπει να αποθηκεύονται.
Φυσικά, μην βάζετε ευαίσθητες πληροφορίες στον κώδικα, καθώς θα είναι δημόσιες.
Για να εξάγετε τη μνήμη από τον browser μπορείτε να dump the process memory ή να πάτε στις ρυθμίσεις της επέκτασης, κάντε κλικ στο Inspect pop-up -> στην ενότητα Memory -> Take a snaphost και CTRL+F για να αναζητήσετε μέσα στο snapshot ευαίσθητες πληροφορίες.
Επιπλέον, πολύ ευαίσθητες πληροφορίες όπως mnemonic keys ή passwords δεν θα πρέπει να επιτρέπεται να αντιγράφονται στο clipboard (ή τουλάχιστον να αφαιρούνται από το clipboard μετά από λίγα δευτερόλεπτα), γιατί τότε διεργασίες που παρακολουθούν το clipboard θα μπορούν να τις αποκτήσουν.
Loading an Extension in the Browser
- Download την επέκταση του browser και αποσυμπιέστε
- Πηγαίνετε στο
chrome://extensions/και ενεργοποιήστε τοDeveloper Mode - Κάντε κλικ στο κουμπί
Load unpacked
Στον Firefox πηγαίνετε στο about:debugging#/runtime/this-firefox και κάντε κλικ στο κουμπί Load Temporary Add-on.
Getting the source code from the store
Ο πηγαίος κώδικας μιας επέκτασης Chrome μπορεί να αποκτηθεί με διάφορες μεθόδους. Παρακάτω υπάρχουν αναλυτικές εξηγήσεις και οδηγίες για κάθε επιλογή.
Download Extension as ZIP via Command Line
Ο πηγαίος κώδικας μιας επέκτασης Chrome μπορεί να κατέβει ως αρχείο ZIP χρησιμοποιώντας τη γραμμή εντολών. Αυτό περιλαμβάνει τη χρήση του curl για να ληφθεί το αρχείο ZIP από μια συγκεκριμένη URL και στη συνέχεια την αποσυμπίεση του περιεχομένου σε έναν φάκελο. Εδώ είναι τα βήματα:
- Αντικαταστήστε το
"extension_id"με το πραγματικό ID της επέκτασης. - Εκτελέστε τις παρακάτω εντολές:
extension_id=your_extension_id # Replace with the actual extension ID
curl -L -o "$extension_id.zip" "https://clients2.google.com/service/update2/crx?response=redirect&os=mac&arch=x86-64&nacl_arch=x86-64&prod=chromecrx&prodchannel=stable&prodversion=44.0.2403.130&x=id%3D$extension_id%26uc"
unzip -d "$extension_id-source" "$extension_id.zip"
Χρήση της ιστοσελίδας CRX Viewer
Χρήση της επέκτασης CRX Viewer
Μία ακόμη βολική μέθοδος είναι η χρήση του Chrome Extension Source Viewer, ένα open-source project. Μπορεί να εγκατασταθεί από το Chrome Web Store. Ο source code του viewer είναι διαθέσιμος στο GitHub repository.
Εμφάνιση πηγαίου κώδικα τοπικά εγκατεστημένης επέκτασης
Μπορείτε επίσης να επιθεωρήσετε Chrome extensions που είναι εγκατεστημένα τοπικά. Να πώς:
- Πρόσβαση στον τοπικό φάκελο προφίλ του Chrome επισκεπτόμενοι
chrome://version/και εντοπίζοντας το πεδίο “Profile Path”. - Πλοηγηθείτε στον υποφάκελο
Extensions/μέσα στον φάκελο προφίλ. - Αυτός ο φάκελος περιέχει όλες τις εγκατεστημένες επεκτάσεις, συνήθως με τον source code τους σε αναγνώσιμη μορφή.
Για να αναγνωρίσετε επεκτάσεις, μπορείτε να αντιστοιχίσετε τα IDs τους με ονόματα:
- Ενεργοποιήστε το Developer Mode στη σελίδα
about:extensionsγια να δείτε τα IDs κάθε επέκτασης. - Μέσα σε κάθε φάκελο επέκτασης, το αρχείο
manifest.jsonπεριέχει το αναγνώσιμο πεδίοname, που βοηθά στην αναγνώριση της επέκτασης.
Χρήση ενός File Archiver ή Unpacker
Πηγαίνετε στο Chrome Web Store και κατεβάστε την επέκταση. Το αρχείο θα έχει επέκταση .crx. Αλλάξτε την επέκταση του αρχείου από .crx σε .zip. Χρησιμοποιήστε οποιονδήποτε file archiver (όπως WinRAR, 7-Zip, κ.λπ.) για να εξαγάγετε τα περιεχόμενα του ZIP αρχείου.
Χρήση του Developer Mode στο Chrome
Ανοίξτε το Chrome και μεταβείτε στο chrome://extensions/. Ενεργοποιήστε “Developer mode” πάνω δεξιά. Κάντε κλικ στο “Load unpacked extension…”. Πλοηγηθείτε στον κατάλογο της επέκτασής σας. Αυτό δεν κατεβάζει τον source code, αλλά είναι χρήσιμο για την προβολή και την τροποποίηση του κώδικα μιας ήδη κατεβασμένης ή αναπτυγμένης επέκτασης.
Chrome extension manifest dataset
In order to try to spot vulnerable browser extensions you could use thehttps://github.com/palant/chrome-extension-manifests-dataset and check their manifest files for potentially vulnerable signs. For example to check for extensions with more than 25000 users, content_scripts and the permission nativeMessaing:
# Query example from https://spaceraccoon.dev/universal-code-execution-browser-extensions/
node query.js -f "metadata.user_count > 250000" "manifest.content_scripts?.length > 0 && manifest.permissions?.includes('nativeMessaging')"
Post-exploitation: Forced extension load & persistence (Windows)
Stealthy τεχνική για backdoor το Chromium με απευθείας επεξεργασία των per-user Preferences και πλαστογράφηση έγκυρων HMACs, προκαλώντας τον browser να αποδεχτεί και να ενεργοποιήσει μια αυθαίρετη unpacked extension χωρίς prompts ή flags.
Forced Extension Load Preferences Mac Forgery Windows
Εντοπισμός Κακόβουλων Ενημερώσεων Επεκτάσεων (Static Version Diffing)
Supply-chain compromsies συχνά έρχονται ως malicious updates σε προηγουμένως benign extensions. Μια πρακτική, low-noise προσέγγιση είναι να συγκρίνετε ένα νέο extension package με την τελευταία known-good έκδοση χρησιμοποιώντας static analysis (για παράδειγμα, Assemblyline). Ο σκοπός είναι να ειδοποιήσετε για high-signal deltas αντί για οποιαδήποτε αλλαγή.
Workflow
- Submit both versions (old + new) στο ίδιο static-analysis profile.
- Flag new or updated background/service worker scripts (persistence + privileged logic).
- Flag new or updated content scripts (DOM access και συλλογή δεδομένων).
- Flag new permissions/host_permissions που προστέθηκαν στο
manifest.json. - Flag new domains εξαγόμενα από τον κώδικα (πιθανά C2/exfil endpoints).
- Flag new static-analysis detections (π.χ., base64 decode, cookie harvesting, network-request builders, patterns obfuscation).
- Flag statistical anomalies όπως απότομες αυξήσεις entropy ή outlier z-scores στα changed scripts.
Detecting script changes accurately
- New script added → ανιχνεύεται μέσω diff του
manifest.json. - Existing script modified (manifest unchanged) → συγκρίνετε per-file hashes από το extracted file tree (π.χ., Assemblyline
Extractoutput). Αυτό συλλαμβάνει stealthy updates σε υπάρχοντες workers ή content scripts.
Pre-disclosure detections
Για να αποφύγετε “easy mode” detections βασισμένα σε ήδη-γνωστά IOCs, disable threat-intel-fed services και στηριχθείτε σε intrinsic signals (domains, heuristic signatures, script deltas, entropy anomalies). Αυτό αυξάνει τις πιθανότητες να πιάσετε malicious updates πριν την δημόσια αναφορά.
Example high-confidence alert logic
- Low-noise combo: new domains + new static-analysis detections + updated background/service worker + updated or added content scripts.
- Broader catch: new domain + new or updated background/service worker (υψηλότερο recall, υψηλότερο noise).
Key Assemblyline services για αυτή τη ροή εργασίας:
- Extract: unpackάρει την extension και παράγει per-file hashes.
- Characterize: υπολογίζει χαρακτηριστικά αρχείων (π.χ., entropy).
- JsJAWS / FrankenStrings / URLCreator: εμφανίζουν JS heuristics, strings, και domains για diff μεταξύ εκδόσεων.
Λίστα Ελέγχου Ασφάλειας
Αν και οι Browser Extensions έχουν μια περιορισμένη attack surface, μερικές μπορεί να περιέχουν vulnerabilities ή potential hardening improvements. Οι παρακάτω είναι οι πιο κοινές:
- Limit όσο γίνεται τα ζητούμενα
permissions - Limit όσο γίνεται τα
host_permissions - Χρήση ισχυρού
content_security_policy - Limit όσο γίνεται το
externally_connectable, αν δεν χρειάζεται και είναι δυνατό, μην το αφήνετε by default, ορίστε{} - Εάν URL ευάλωτο σε XSS ή takeover αναφέρεται εδώ, ένας επιτιθέμενος θα μπορεί να στέλνει μηνύματα στα background scripts απευθείας. Πολύ ισχυρό bypass.
- Limit όσο γίνεται τα
web_accessible_resources, ακόμα και κενά αν είναι δυνατό. - Εάν
web_accessible_resourcesδεν είναι none, ελέγξτε για ClickJacking - Εάν οποιαδήποτε επικοινωνία γίνεται από την extension προς τη web page, ελέγξτε για XSS vulnerabilities που προκαλούνται στην επικοινωνία.
- Εάν χρησιμοποιούνται Post Messages, ελέγξτε για Post Message vulnerabilities.
- Εάν το Content Script έχει access στο DOM, ελέγξτε ότι δεν εισάγει XSS εάν τροποποιείται από τον ιστό.
- Δώστε ειδική έμφαση αν αυτή η επικοινωνία εμπλέκει επίσης την Content Script -> Background script communication
- Εάν το background script επικοινωνεί μέσω native messaging ελέγξτε ότι η επικοινωνία είναι secure και sanitized
- Sensitive information δεν πρέπει να αποθηκεύεται μέσα στον κώδικα της Browser Extension
- Sensitive information δεν πρέπει να αποθηκεύεται μέσα στη μνήμη της Browser Extension
- Sensitive information δεν πρέπει να αποθηκεύεται στο file system unprotected
Browser Extension Risks
- Η εφαρμογή https://crxaminer.tech/ αναλύει δεδομένα όπως τα permissions που ζητάει μια browser extension για να δώσει ένα risk level χρήσης της extension.
Tools
Tarnish
- Κατεβάζει οποιοδήποτε Chrome extension από ένα παρεχόμενο Chrome webstore link.
- manifest.json viewer: εμφανίζει απλά μια JSON-prettified έκδοση του manifest της extension.
- Fingerprint Analysis: Ανίχνευση των web_accessible_resources και αυτόματη δημιουργία fingerprinting JavaScript για Chrome extensions.
- Potential Clickjacking Analysis: Ανίχνευση σελίδων HTML της extension με το directive web_accessible_resources ενεργό. Αυτές μπορεί να είναι πιθανώς ευάλωτες σε clickjacking ανάλογα με τον σκοπό των σελίδων.
- Permission Warning(s) viewer: εμφανίζει τη λίστα με όλα τα Chrome permission prompt warnings που θα εμφανιστούν όταν ένας χρήστης προσπαθήσει να εγκαταστήσει την extension.
- Dangerous Function(s): δείχνει την τοποθεσία επικίνδυνων function που ενδέχεται να εκμεταλλευτούν επιτιθέμενοι (π.χ. functions όπως innerHTML, chrome.tabs.executeScript).
- Entry Point(s): δείχνει που η extension δέχεται input από χρήστη/εξωτερικές πηγές. Χρήσιμο για να κατανοήσετε την επιφάνεια επίθεσης και να ψάξετε πιθανούς points για να στείλετε maliciously-crafted δεδομένα στην extension.
- Τα Dangerous Function(s) και Entry Point(s) scanners παρέχουν για τα alerts:
- Σχετικό code snippet και γραμμή που προκάλεσε το alert.
- Περιγραφή του ζητήματος.
- Ένα κουμπί “View File” για να δείτε το πλήρες source file που περιέχει τον κώδικα.
- Το path του alerted αρχείου.
- Το πλήρες Chrome extension URI του alerted αρχείου.
- Τον τύπο του αρχείου, όπως Background Page script, Content Script, Browser Action, κ.λπ.
- Εάν η ευάλωτη γραμμή είναι σε JavaScript αρχείο, τα paths όλων των σελίδων όπου συμπεριλαμβάνεται καθώς και ο τύπος αυτών των σελίδων και η web_accessible_resource κατάσταση.
- Content Security Policy (CSP) analyzer and bypass checker: Επισημαίνει αδυναμίες στο CSP της extension και δείχνει πιθανούς τρόπους bypass λόγω whitelisted CDNs κ.λπ.
- Known Vulnerable Libraries: Χρησιμοποιεί Retire.js για να ελέγξει για χρήση γνωστών-vulnerable JavaScript βιβλιοθηκών.
- Download extension και formatted versions.
- Download του original extension.
- Download μιας beautified έκδοσης της extension (auto prettified HTML και JavaScript).
- Αυτόματη caching των scan results — μια σάρωση θα πάρει χρόνο την πρώτη φορά, αλλά τη δεύτερη φορά (αν η extension δεν έχει ενημερωθεί) θα είναι σχεδόν άμεση λόγω cache.
- Linkable Report URLs, εύκολο να στείλετε το report σε κάποιον.
Neto
Το Project Neto είναι ένα Python 3 package σχεδιασμένο για ανάλυση και αποκάλυψη κρυφών χαρακτηριστικών browser plugins και extensions για γνωστούς browsers όπως Firefox και Chrome. Αυτοματοποιεί τη διαδικασία unzip των πακεταρισμένων αρχείων για εξαγωγή χαρακτηριστικών από resources της extension όπως manifest.json, localization folders ή Javascript και HTML source files.
Αναφορές
- 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:
HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Μάθετε & εξασκηθείτε στο Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Υποστηρίξτε το HackTricks
- Ελέγξτε τα σχέδια συνδρομής!
- Εγγραφείτε στην 💬 ομάδα Discord ή στην ομάδα telegram ή ακολουθήστε μας στο Twitter 🐦 @hacktricks_live.
- Μοιραστείτε κόλπα hacking υποβάλλοντας PRs στα HackTricks και HackTricks Cloud github repos.


