hacktricks/src/pentesting-web/browser-extension-pentesting-methodology

Μεθοδολογία Browser Extension Pentesting

{{#include ../../banners/hacktricks-training.md}}

Βασικές Πληροφορίες

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

Κύρια Συστατικά

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

http://webblaze.cs.berkeley.edu/papers/Extensions.pdf

Content Scripts

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

Extension Core

Το extension core περιέχει τα περισσότερα από τα προνόμια/προσβάσεις της επέκτασης, αλλά το extension core μπορεί να αλληλεπιδρά με web content μόνο μέσω 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.

Boundaries

Caution

Για να αποκτήσει τα πλήρη προνόμια του χρήστη, ένας επιτιθέμενος πρέπει να πείσει την επέκταση να μεταφέρει κακόβουλη είσοδο από το content script στον πυρήνα της επέκτασης (extension's core) και από τον πυρήνα της επέκτασης στο native binary.

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

Επιπλέον, τα content scripts διαχωρίζονται από τις αντίστοιχες web pages τους τρέχοντας σε ξεχωριστό JavaScript heap. Το content script και η web page έχουν πρόσβαση στο ίδιο υποκείμενο DOM, αλλά τα δύο ποτέ δεν ανταλλάσσουν JavaScript pointers, αποτρέποντας το leaking της JavaScript λειτουργικότητας.

manifest.json

Μια Chrome extension είναι απλώς ένας φάκελος 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*"],
}
],

Για να συμπεριλάβετε ή να εξαιρέσετε περισσότερες διευθύνσεις URL, είναι επίσης δυνατό να χρησιμοποιήσετε include_globs και exclude_globs.

Αυτό είναι ένα παράδειγμα content script το οποίο θα προσθέσει ένα explain κουμπί στη σελίδα όταν χρησιμοποιηθεί the storage API για να ανακτήσει την τιμή message από το 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)
})

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

Warning

Ανάλογα με τον browser, οι δυνατότητες του content script ενδέχεται να διαφέρουν ελαφρώς. Για browsers βάσει Chromium, η λίστα δυνατοτήτων είναι διαθέσιμη στην 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. Αυτό επιτρέπει την παρακολούθηση των ενεργών content scripts από διάφορες επεκτάσεις και τον ορισμό breakpoints για την παρακολούθηση της ροής εκτέλεσης.

Ενέσιμα content scripts

Tip

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

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

Παράδειγμα επέκτασης που βασίζεται στο activeTab

{
"name": "My extension",
...
"permissions": [
"activeTab",
"scripting"
],
"background": {
"service_worker": "background.js"
},
"action": {
"default_title": "Action Button"
}
}
  • Εισαγωγή αρχείου JS με κλικ:
// content-script.js
document.body.style.backgroundColor = "orange"

//service-worker.js - Inject the JS file
chrome.action.onClicked.addListener((tab) => {
chrome.scripting.executeScript({
target: { tabId: tab.id },
files: ["content-script.js"],
})
})
  • Inject a function όταν γίνεται κλικ:
//service-worker.js - Inject a function
function injectedFunction() {
document.body.style.backgroundColor = "orange"
}

chrome.action.onClicked.addListener((tab) => {
chrome.scripting.executeScript({
target: { tabId: tab.id },
func: injectedFunction,
})
})

Παράδειγμα με δικαιώματα 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.

Content Scripts run_at

Το πεδίο run_at ελέγχει πότε τα αρχεία JavaScript εγχέονται στη σελίδα web. Η προτιμώμενη και προεπιλεγμένη τιμή είναι "document_idle".

Οι δυνατές τιμές είναι:

  • document_idle: Όποτε είναι δυνατόν
  • document_start: Μετά από αρχεία από το css, αλλά πριν κατασκευαστεί οποιοδήποτε άλλο DOM ή πριν εκτελεστεί οποιοδήποτε άλλο script.
  • document_end: Άμεσα μετά την ολοκλήρωση του DOM, αλλά πριν φορτωθούν υπο-πόροι όπως εικόνες και 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, η οποία λειτουργεί ως κεντρικός κόμβος συντονισμού των συστατικών του extension. Σημειωτέον, η background page παραμένει καθ' όλη τη διάρκεια ζωής του extension, λειτουργώντας αθόρυβα χωρίς άμεση αλληλεπίδραση με τον χρήστη. Διαθέτει το δικό της Document Object Model (DOM), επιτρέποντας πολύπλοκες αλληλεπιδράσεις και διαχείριση κατάστασης.

Κύρια Σημεία:

  • Background Page Role: Λειτουργεί ως κέντρο νεύρων για το extension, εξασφαλίζοντας επικοινωνία και συντονισμό μεταξύ των διαφόρων μερών του extension.
  • Persistence: Είναι μια πάντα παρούσα οντότητα, αόρατη στον χρήστη αλλά ουσιαστική για τη λειτουργικότητα του extension.
  • Automatic Generation: Αν δεν οριστεί ρητά, ο browser θα δημιουργήσει αυτόματα μια background page. Αυτή η αυτόματα δημιουργημένη σελίδα θα περιλαμβάνει όλα τα background scripts που καθορίζονται στο manifest του extension, εξασφαλίζοντας την απρόσκοπτη λειτουργία των background tasks του extension.

Tip

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

Παράδειγμα 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 για να ανοίξει μια σελίδα σε νέα καρτέλα.

Για να κάνετε debug το background script μπορείτε να μεταβείτε στις extension details and inspect the service worker, αυτό θα ανοίξει τα developer tools με το background script:

Options pages and other

Browser extensions μπορούν να περιέχουν διάφορους τύπους σελίδων:

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

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

  • Επικοινωνία με Content Scripts: Όπως και με το background page, αυτές οι σελίδες μπορούν να λάβουν μηνύματα από content scripts, διευκολύνοντας την αλληλεπίδραση μέσα στην επέκταση.
  • Πρόσβαση σε Extension-Specific APIs: Αυτές οι σελίδες έχουν πλήρη πρόσβαση σε extension-specific APIs, υπό τις άδειες (permissions) που ορίζονται για την επέκταση.

permissions & host_permissions

permissions and host_permissions είναι εγγραφές στο manifest.json που υποδεικνύουν ποιες άδειες έχει η επέκταση (storage, location...) και σε ποιες ιστοσελίδες.

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

Check how these settings work and how they could get abused in:

{{#ref}} browext-permissions-and-host_permissions.md {{#endref}}

content_security_policy

A content security policy μπορεί επίσης να δηλωθεί μέσα στο manifest.json. Εάν έχει οριστεί, μπορεί να είναι ευάλωτη.

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

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

For more info about CSP and potential bypasses check:

{{#ref}} ../content-security-policy-csp-bypass/ {{#endref}}

web_accessible_resources

Για να μπορεί μια ιστοσελίδα να έχει πρόσβαση σε μια σελίδα ενός Browser Extension, για παράδειγμα μια .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:

Although, if the manifest.json parameter use_dynamic_url is used, this id can be dynamic.

Tip

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

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

{{#ref}} browext-clickjacking.md {{#endref}}

Tip

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

Caution

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

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

externally_connectable

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

  • Αν το κλειδί externally_connectable δεν δηλώνεται στο manifest της επέκτασής σας ή δηλώνεται ως "ids": ["*"], όλες οι επεκτάσεις μπορούν να συνδεθούν, αλλά καμία ιστοσελίδα δεν μπορεί.
  • Αν δηλωθούν συγκεκριμένα IDs, όπως στο "ids": ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"], μόνο αυτές οι εφαρμογές μπορούν να συνδεθούν.
  • Αν δηλωθούν matches, αυτές οι web apps θα μπορούν να συνδεθούν:
"matches": [
"https://*.google.com/*",
"*://*.chromium.org/*",
  • Εάν οριστεί ως κενό: "externally_connectable": {}, καμία εφαρμογή ή ιστότοπος δεν θα μπορεί να συνδεθεί.

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

Caution

Εάν μια σελίδα web vulnerable to XSS or takeover αναφέρεται στο externally_connectable, ένας attacker θα μπορεί να send messages directly to the background script, παρακάμπτοντας πλήρως το Content Script και το CSP του.

Επομένως, αυτό είναι ένα πολύ ισχυρό bypass.

Επιπλέον, εάν ο client εγκαταστήσει μια rouge extension, ακόμη και αν δεν επιτρέπεται να επικοινωνήσει με την vulnerable extension, θα μπορούσε να εγχύσει XSS data in an allowed web page ή να καταχραστεί τα WebRequest ή DeclarativeNetRequest APIs για να χειριστεί requests σε έναν στοχευμένο domain, τροποποιώντας το request της σελίδας για ένα JavaScript file. (Σημειώστε ότι το CSP στη στοχευμένη σελίδα θα μπορούσε να αποτρέψει αυτές τις επιθέσεις). Αυτή η ιδέα προέρχεται from this writeup.

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

Extension <--> WebApp

Για την επικοινωνία μεταξύ του content script και της σελίδας web συνήθως χρησιμοποιούνται post messages. Επομένως, στην web application συνήθως θα βρείτε κλήσεις στη συνάρτηση window.postMessage και στο content script listeners όπως window.addEventListener. Σημειώστε όμως ότι το extension θα μπορούσε επίσης να communicate with the web application sending a Post Message (και επομένως η web πρέπει να το περιμένει) ή απλώς να κάνει την web να φορτώσει ένα νέο script.

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

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

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

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 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: μπορεί να επιτρέπει μηνύματα μόνο από domains που βρίσκονται στην allowlist.
  • Αν χρησιμοποιείται regex, να είστε πολύ προσεκτικοί
  • Source: received_message.source !== window μπορεί να χρησιμοποιηθεί για να ελεγχθεί αν το μήνυμα ήταν από το ίδιο παράθυρο όπου το Content Script ακούει.

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

{{#ref}} ../postmessage-vulnerabilities/ {{#endref}}

Iframe

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

{{#ref}} browext-xss-example.md {{#endref}}

DOM

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

Μπορείτε επίσης να βρείτε ένα παράδειγμα DOM based XSS to compromise a browser extension στο:

{{#ref}} browext-xss-example.md {{#endref}}

Content Script ↔︎ Background Script Communication

Ένα Content Script μπορεί να χρησιμοποιήσει τις συναρτήσεις runtime.sendMessage() ή tabs.sendMessage() για να στείλει ένα one-time 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)
})()

Αποστολή ενός αιτήματος από το extension (συνήθως ένα background script). Παράδειγμα για το πώς να στείλετε μήνυμα στο content script στην selected tab:

// 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 ώστε το sendResponse() να εκτελείται ασύγχρονα, είναι απαραίτητο να συμπεριληφθεί το return true;.

Σημαντικό ζήτημα είναι ότι σε σενάρια όπου πολλαπλές σελίδες λαμβάνουν onMessage συμβάντα, η πρώτη σελίδα που θα εκτελέσει το sendResponse() για ένα συγκεκριμένο συμβάν θα είναι η μόνη που θα μπορέσει να παραδώσει την απάντηση αποτελεσματικά. Οποιεσδήποτε επακόλουθες απαντήσεις στο ίδιο συμβάν δεν θα ληφθούν υπόψη.

Κατά τη δημιουργία νέων extensions, η προτίμηση πρέπει να είναι προς promises αντί για callbacks. Όσον αφορά τη χρήση callbacks, η συνάρτηση sendResponse() θεωρείται έγκυρη μόνο εάν εκτελείται απευθείας στο συγχρονικό πλαίσιο, ή εάν ο χειριστής συμβάντος δηλώνει ασύγχρονη λειτουργία επιστρέφοντας true. Εάν κανένας από τους χειριστές δεν επιστρέψει true ή αν η sendResponse() αφαιρεθεί από τη μνήμη (garbage-collected), το callback που σχετίζεται με τη sendMessage() θα εκτελεστεί από προεπιλογή.

Native Messaging

Τα browser extensions επιτρέπουν επίσης την επικοινωνία με binaries in the system via stdin. Η εφαρμογή πρέπει να εγκαταστήσει ένα json που το δηλώνει σε ένα json σαν:

{
"name": "com.my_company.my_application",
"description": "My Application",
"path": "C:\\Program Files\\My Application\\chrome_native_messaging_host.exe",
"type": "stdio",
"allowed_origins": ["chrome-extension://knldjmfmopnpolahpmmgbagdohdnhkik/"]
}

Όπου το name είναι η συμβολοσειρά που δίνεται σε runtime.connectNative() ή σε runtime.sendNativeMessage() για να επικοινωνήσει με την εφαρμογή από τα background scripts της επέκτασης προγράμματος περιήγησης. Το path είναι η διαδρομή προς το binary, υπάρχει μόνο 1 έγκυρο type το οποίο είναι stdio (χρησιμοποιεί stdin και stdout) και τα allowed_origins δείχνουν ποιες επεκτάσεις μπορούν να έχουν πρόσβαση (και δεν μπορούν να περιέχουν wildcard).

Chrome/Chromium θα ψάξει για αυτό το json στο Windows registry και σε μερικά paths σε macOS και Linux (περισσότερες πληροφορίες στα docs).

Tip

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

Έτσι μοιάζει ένας κώδικας 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:

  1. Η επέκταση προγράμματος περιήγησης έχει ένα wildcard pattern για το content script.
  2. Το content script προωθεί μηνύματα postMessage στο background script χρησιμοποιώντας sendMessage.
  3. Το background script προωθεί το μήνυμα στην native εφαρμογή χρησιμοποιώντας sendNativeMessage.
  4. Η native εφαρμογή χειρίζεται το μήνυμα επικίνδυνα, οδηγώντας σε code execution.

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

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

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

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

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

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

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

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

  1. Κατεβάστε την επέκταση προγράμματος περιήγησης και αποσυμπιέστε την
  2. Πηγαίνετε στο chrome://extensions/ και ενεργοποιήστε το Developer Mode
  3. Κάντε κλικ στο κουμπί Load unpacked

Στον Firefox πηγαίνετε στο about:debugging#/runtime/this-firefox και κάντε κλικ στο κουμπί Load Temporary Add-on.

Απόκτηση του source code από το store

Ο πηγαίος κώδικας μιας επέκτασης 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 τους σε ονόματα:

  • Ενεργοποιήστε το Developer Mode στη σελίδα about:extensions για να δείτε τα IDs κάθε επέκτασης.
  • Μέσα στον φάκελο κάθε επέκτασης, το αρχείο manifest.json περιέχει ένα αναγνώσιμο πεδίο name, που βοηθά στην αναγνώριση της επέκτασης.

Χρησιμοποιήστε ένα εργαλείο αρχειοθέτησης ή αποσυμπίεσης

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

Χρησιμοποιήστε το Developer Mode στο Chrome

Ανοίξτε το Chrome και πηγαίνετε στο chrome://extensions/. Ενεργοποιήστε το "Developer mode" επάνω δεξιά. Κάντε κλικ στο "Load unpacked extension...". Πλοηγηθείτε στον κατάλογο της επέκτασής σας. Αυτό δεν κατεβάζει τον πηγαίο κώδικα, αλλά είναι χρήσιμο για την προβολή και την τροποποίηση του κώδικα μιας ήδη κατεβασμένης ή αναπτυγμένης επέκτασης.

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

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

# Query example from https://spaceraccoon.dev/universal-code-execution-browser-extensions/
node query.js -f "metadata.user_count > 250000" "manifest.content_scripts?.length > 0 && manifest.permissions?.includes('nativeMessaging')"

Post-exploitation: Forced extension load & persistence (Windows)

Stealthy τεχνική για να backdoor το Chromium με άμεση επεξεργασία των per-user Preferences και πλαστογράφηση έγκυρων HMACs, προκαλώντας τον browser να αποδεχτεί και να ενεργοποιήσει ένα αυθαίρετο unpacked extension χωρίς prompts ή flags.

{{#ref}} forced-extension-load-preferences-mac-forgery-windows.md {{#endref}}

Λίστα ελέγχου ασφάλειας

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

  • Περιορίστε όσο το δυνατό περισσότερο τα ζητούμενα permissions
  • Περιορίστε όσο το δυνατό περισσότερο τα host_permissions
  • Χρησιμοποιήστε μια ισχυρή content_security_policy
  • Περιορίστε όσο το δυνατό περισσότερο το externally_connectable, αν δεν απαιτείται και είναι δυνατόν, μην το αφήνετε από προεπιλογή, καθορίστε {}
  • Αν εδώ αναφέρεται URL που είναι ευάλωτο σε XSS ή takeover, ένας attacker θα μπορέσει να στέλνει μηνύματα στα background scripts απευθείας. Πολύ ισχυρή παράκαμψη.
  • Περιορίστε όσο το δυνατό περισσότερο τα web_accessible_resources, ακόμα και κενά αν είναι δυνατόν.
  • Αν τα web_accessible_resources δεν είναι none, ελέγξτε για ClickJacking
  • Αν οποιαδήποτε επικοινωνία γίνεται από την επέκταση προς τη σελίδα web, ελέγξτε για XSS ευπάθειες που προκαλούνται στην επικοινωνία.
  • Αν χρησιμοποιούνται Post Messages, ελέγξτε για Post Message vulnerabilities.
  • Αν το Content Script έχει πρόσβαση σε λεπτομέρειες του DOM, ελέγξτε ότι δεν εισάγουν XSS αν τροποποιηθούν από το web
  • Δώστε ειδική έμφαση αν αυτή η επικοινωνία εμπλέκεται επίσης στην Content Script -> Background script communication
  • Αν το background script επικοινωνεί μέσω native messaging ελέγξτε ότι η επικοινωνία είναι ασφαλής και γίνεται sanitization
  • Ευαίσθητες πληροφορίες δεν πρέπει να αποθηκεύονται μέσα στον κώδικα της επέκτασης
  • Ευαίσθητες πληροφορίες δεν πρέπει να αποθηκεύονται στη μνήμη της επέκτασης
  • Ευαίσθητες πληροφορίες δεν πρέπει να αποθηκεύονται στο file system unprotected

Κίνδυνοι επεκτάσεων προγράμματος περιήγησης

  • Η εφαρμογή https://crxaminer.tech/ αναλύει κάποια δεδομένα όπως τα permissions που ζητάει μια επέκταση για να δώσει ένα επίπεδο κινδύνου χρήσης της επέκτασης.

Εργαλεία

Tarnish

  • Κατεβάζει οποιαδήποτε Chrome extension από ένα δοθέν Chrome webstore link.
  • manifest.json viewer: απλά εμφανίζει μια JSON-prettified έκδοση του manifest της επέκτασης.
  • Fingerprint Analysis: Ανίχνευση των web_accessible_resources και αυτόματη δημιουργία Chrome extension fingerprinting JavaScript.
  • Potential Clickjacking Analysis: Ανίχνευση HTML σελίδων της επέκτασης με τη ρύθμιση web_accessible_resources. Αυτές είναι δυνητικά ευάλωτες σε clickjacking ανάλογα με τον σκοπό των σελίδων.
  • Permission Warning(s) viewer: δείχνει μια λίστα με όλες τις προειδοποιήσεις αδειών Chrome που θα εμφανιστούν όταν ένας χρήστης προσπαθήσει να εγκαταστήσει την επέκταση.
  • Dangerous Function(s): δείχνει τη θέση επικίνδυνων συναρτήσεων που θα μπορούσαν δυνητικά να εκμεταλλευτούνται από έναν attacker (π.χ. συναρτήσεις όπως innerHTML, chrome.tabs.executeScript).
  • Entry Point(s): δείχνει από πού η επέκταση λαμβάνει input από χρήστη/εξωτερικό. Αυτό είναι χρήσιμο για να κατανοήσετε την επιφάνεια της επέκτασης και να εντοπίσετε πιθανά σημεία για αποστολή κακόβουλων δεδομένων στην επέκταση.
  • Οι σαρωτές Dangerous Function(s) και Entry Point(s) παρέχουν για τις ειδοποιήσεις που δημιουργούν:
    • Σχετικό απόσπασμα κώδικα και γραμμή που προκάλεσε την ειδοποίηση.
    • Περιγραφή του ζητήματος.
    • Ένα κουμπί “View File” για να δείτε το πλήρες αρχείο πηγαίου κώδικα που περιέχει τον κώδικα.
    • Το path του αρχείου που προκάλεσε την ειδοποίηση.
    • Το πλήρες Chrome extension URI του αρχείου.
    • Τον τύπο αρχείου (π.χ. Background Page script, Content Script, Browser Action, κ.λπ.).
    • Αν η ευάλωτη γραμμή είναι σε JavaScript αρχείο, τα paths όλων των σελίδων όπου αυτό συμπεριλαμβάνεται καθώς και ο τύπος αυτών των σελίδων και η web_accessible_resource κατάσταση.
  • Content Security Policy (CSP) analyzer and bypass checker: Θα επισημάνει αδυναμίες στο CSP της επέκτασής σας και θα φωτίσει τυχόν πιθανούς τρόπους παράκαμψης του CSP λόγω whitelisted CDNs, κ.λπ.
  • Known Vulnerable Libraries: Χρησιμοποιεί Retire.js για να ελέγξει για χρήση γνωστών ευάλωτων βιβλιοθηκών JavaScript.
  • Κατεβάζει την επέκταση και μορφοποιημένες εκδόσεις.
  • Κατεβάζει την πρωτότυπη επέκταση.
  • Κατεβάζει μια beautified έκδοση της επέκτασης (αυτόματη ομορφοποίηση HTML και JavaScript).
  • Αυτόματη caching των αποτελεσμάτων σάρωσης — μια σάρωση επέκτασης θα πάρει αρκετό χρόνο την πρώτη φορά που θα τη τρέξετε. Ωστόσο η δεύτερη φορά, αν υποθέσουμε ότι η επέκταση δεν έχει ενημερωθεί, θα είναι σχεδόν άμεση λόγω της προσωρινής αποθήκευσης των αποτελεσμάτων.
  • Linkable Report URLs, εύκολο να στείλετε σε κάποιον άλλο μια αναφορά επέκτασης που παράχθηκε από tarnish.

Neto

Το Project Neto είναι ένα Python 3 package σχεδιασμένο για να αναλύει και να αποκαλύπτει κρυφές δυνατότητες browser plugins και extensions για γνωστούς browsers όπως Firefox και Chrome. Αυτοματοποιεί τη διαδικασία αποσυμπίεσης των πακεταρισμένων αρχείων για εξαγωγή αυτών των δυνατοτήτων από σχετικούς πόρους σε μια extension όπως manifest.json, φακέλους localization ή πηγαία αρχεία Javascript και HTML.

Αναφορές

{{#include ../../banners/hacktricks-training.md}}