.. | ||
browext-clickjacking.md | ||
browext-permissions-and-host_permissions.md | ||
browext-xss-example.md | ||
README.md |
Browser Extension Pentesting Methodology
{% hint style="success" %}
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Support HackTricks
- Check the subscription plans!
- Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.
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
{% hint style="danger" %} Για να αποκτήσει τα πλήρη προνόμια του χρήστη, ένας επιτιθέμενος πρέπει να πείσει την επέκταση να περάσει κακόβουλη είσοδο από το script περιεχομένου στον πυρήνα της επέκτασης και από τον πυρήνα της επέκτασης στη εγγενή δυαδική. {% endhint %}
Κάθε στοιχείο της επέκτασης είναι χωρισμένο το ένα από το άλλο με ισχυρά προστατευτικά όρια. Κάθε στοιχείο εκτελείται σε μια ξεχωριστή διαδικασία λειτουργικού συστήματος. Τα 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 που θα προσθέσει ένα κουμπί εξήγησης στη σελίδα όταν η 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 μπορούν να επικοινωνούν.
{% hint style="warning" %}
Ανάλογα με τον περιηγητή, οι δυνατότητες του περιεχομένου script μπορεί να διαφέρουν ελαφρώς. Για τους περιηγητές που βασίζονται σε Chromium, η λίστα δυνατοτήτων είναι διαθέσιμη στην τεκμηρίωση Chrome Developers, και για τον Firefox, το MDN χρησιμεύει ως η κύρια πηγή.
Είναι επίσης αξιοσημείωτο ότι τα περιεχόμενα scripts έχουν τη δυνατότητα να επικοινωνούν με τα background scripts, επιτρέποντάς τους να εκτελούν ενέργειες και να μεταφέρουν απαντήσεις πίσω.
{% endhint %}
Για την προβολή και την αποσφαλμάτωση των περιεχομένων scripts στο Chrome, το μενού εργαλείων προγραμματιστών Chrome μπορεί να προσπελαστεί από Επιλογές > Περισσότερα εργαλεία > Εργαλεία προγραμματιστών Ή πατώντας Ctrl + Shift + I.
Αφού εμφανιστούν τα εργαλεία προγραμματιστών, πρέπει να κάνετε κλικ στην καρτέλα Πηγή, ακολουθούμενη από την καρτέλα Περιεχόμενα Scripts. Αυτό επιτρέπει την παρακολούθηση των εκτελούμενων περιεχομένων scripts από διάφορες επεκτάσεις και την ρύθμιση σημείων διακοπής για την παρακολούθηση της ροής εκτέλεσης.
Εισαγόμενα περιεχόμενα scripts
{% hint style="success" %}
Σημειώστε ότι Τα Περιεχόμενα Scripts δεν είναι υποχρεωτικά καθώς είναι επίσης δυνατή η δυναμική εισαγωγή scripts και η προγραμματική εισαγωγή τους σε ιστοσελίδες μέσω του tabs.executeScript
. Αυτό παρέχει στην πραγματικότητα περισσότερους λεπτομερείς ελέγχους.
{% endhint %}
Για την προγραμματική εισαγωγή ενός περιεχομένου script, απαιτείται η επέκταση να έχει δικαιώματα φιλοξενίας για τη σελίδα στην οποία θα εισαχθούν τα scripts. Αυτά τα δικαιώματα μπορεί να εξασφαλιστούν είτε ζητώντας τα μέσα στο μανιφέστο της επέκτασης είτε προσωρινά μέσω του activeTab.
Παράδειγμα επέκτασης βασισμένης σε activeTab
{% code title="manifest.json" %}
{
"name": "My extension",
...
"permissions": [
"activeTab",
"scripting"
],
"background": {
"service_worker": "background.js"
},
"action": {
"default_title": "Action Button"
}
}
{% endcode %}
- Εισαγωγή ενός αρχείου 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), επιτρέποντας πολύπλοκες αλληλεπιδράσεις και διαχείριση καταστάσεων.
Βασικά Σημεία:
- Ρόλος Σελίδας Φόντου: Λειτουργεί ως το κέντρο ελέγχου της επέκτασης, εξασφαλίζοντας την επικοινωνία και τον συντονισμό μεταξύ των διαφόρων τμημάτων της επέκτασης.
- Επιμονή: Είναι μια πάντα παρούσα οντότητα, αόρατη στον χρήστη αλλά αναγκαία για τη λειτουργικότητα της επέκτασης.
- Αυτόματη Δημιουργία: Εάν δεν οριστεί ρητά, ο περιηγητής θα δημιουργήσει αυτόματα μια σελίδα φόντου. Αυτή η αυτόματα δημιουργημένη σελίδα θα περιλαμβάνει όλα τα σενάρια φόντου που καθορίζονται στο μανιφέστο της επέκτασης, εξασφαλίζοντας την απρόσκοπτη λειτουργία των εργασιών φόντου της επέκτασης.
{% hint style="success" %} Η ευκολία που παρέχει ο περιηγητής στην αυτόματη δημιουργία μιας σελίδας φόντου (όταν δεν δηλώνεται ρητά) εξασφαλίζει ότι όλα τα απαραίτητα σενάρια φόντου είναι ενσωματωμένα και λειτουργικά, απλοποιώντας τη διαδικασία ρύθμισης της επέκτασης. {% endhint %}
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
που θα υποδεικνύουν ποιες άδειες έχει η επέκταση του προγράμματος περιήγησης (αποθήκευση, τοποθεσία...) και σε ποιες ιστοσελίδες.
Καθώς οι επεκτάσεις προγράμματος περιήγησης μπορεί να είναι τόσο προνομιούχες, μια κακόβουλη ή μια που έχει παραβιαστεί θα μπορούσε να επιτρέψει στον επιτιθέμενο διαφορετικούς τρόπους να κλέψει ευαίσθητες πληροφορίες και να κατασκοπεύσει τον χρήστη.
Ελέγξτε πώς λειτουργούν αυτές οι ρυθμίσεις και πώς θα μπορούσαν να καταχραστούν σε:
{% content-ref url="browext-permissions-and-host_permissions.md" %} browext-permissions-and-host_permissions.md {% endcontent-ref %}
content_security_policy
Μια πολιτική ασφαλείας περιεχομένου μπορεί επίσης να δηλωθεί μέσα στο manifest.json
. Εάν υπάρχει μία καθορισμένη, θα μπορούσε να είναι ευάλωτη.
Η προεπιλεγμένη ρύθμιση για τις σελίδες επεκτάσεων προγράμματος περιήγησης είναι μάλλον περιοριστική:
script-src 'self'; object-src 'self';
Για περισσότερες πληροφορίες σχετικά με το CSP και τις πιθανές παρακάμψεις, ελέγξτε:
{% content-ref url="../content-security-policy-csp-bypass/" %} content-security-policy-csp-bypass {% endcontent-ref %}
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 μπορεί να είναι δυναμικό.
{% hint style="success" %} Σημειώστε ότι ακόμη και αν μια σελίδα αναφέρεται εδώ, μπορεί να είναι προστατευμένη από ClickJacking χάρη στην Πολιτική Ασφαλείας Περιεχομένου. Έτσι, πρέπει επίσης να το ελέγξετε (τμήμα frame-ancestors) πριν επιβεβαιώσετε ότι είναι δυνατή μια επίθεση ClickJacking. {% endhint %}
Η δυνατότητα πρόσβασης σε αυτές τις σελίδες καθιστά αυτές τις σελίδες πιθανώς ευάλωτες σε ClickJacking:
{% content-ref url="browext-clickjacking.md" %} browext-clickjacking.md {% endcontent-ref %}
{% hint style="success" %} Η επιτρεπόμενη φόρτωση αυτών των σελίδων μόνο από την επέκταση και όχι από τυχαία URLs θα μπορούσε να αποτρέψει επιθέσεις ClickJacking. {% endhint %}
{% hint style="danger" %}
Σημειώστε ότι οι σελίδες από web_accessible_resources
και άλλες σελίδες της επέκτασης είναι επίσης ικανές να επικοινωνούν με σενάρια φόντου. Έτσι, αν μία από αυτές τις σελίδες είναι ευάλωτη σε XSS, θα μπορούσε να ανοίξει μια μεγαλύτερη ευπάθεια.
Επιπλέον, σημειώστε ότι μπορείτε να ανοίξετε μόνο σελίδες που αναφέρονται σε web_accessible_resources
μέσα σε iframes, αλλά από μια νέα καρτέλα είναι δυνατή η πρόσβαση σε οποιαδήποτε σελίδα στην επέκταση γνωρίζοντας το ID της επέκτασης. Επομένως, αν βρεθεί XSS που εκμεταλλεύεται τις ίδιες παραμέτρους, θα μπορούσε να εκμεταλλευτεί ακόμη και αν η σελίδα δεν είναι ρυθμισμένη σε web_accessible_resources
.
{% endhint %}
externally_connectable
Σύμφωνα με τα docs, Η ιδιότητα μανιφέστ "externally_connectable"
δηλώνει ποια extensions και ιστοσελίδες μπορούν να συνδεθούν με την επέκτασή σας μέσω runtime.connect και runtime.sendMessage.
- Αν το
externally_connectable
κλειδί δεν δηλώνεται στο μανιφέστο της επέκτασής σας ή δηλώνεται ως"ids": ["*"]
, όλες οι επεκτάσεις μπορούν να συνδεθούν, αλλά καμία ιστοσελίδα δεν μπορεί να συνδεθεί. - Αν καθορισμένα IDs αναφέρονται, όπως στο
"ids": ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"]
, μόνο αυτές οι εφαρμογές μπορούν να συνδεθούν. - Αν καθοριστούν matches, αυτές οι διαδικτυακές εφαρμογές θα μπορούν να συνδεθούν:
"matches": [
"https://*.google.com/*",
"*://*.chromium.org/*",
- Αν έχει καθοριστεί ως κενό:
"externally_connectable": {}
, καμία εφαρμογή ή ιστότοπος δεν θα μπορεί να συνδεθεί.
Οι λιγότερες επεκτάσεις και διευθύνσεις URL που αναφέρονται εδώ, τόσο μικρότερη θα είναι η επιφάνεια επίθεσης.
{% hint style="danger" %}
Αν μια ιστοσελίδα ευάλωτη σε XSS ή takeover αναφέρεται σε externally_connectable
, ένας επιτιθέμενος θα μπορεί να στείλει μηνύματα απευθείας στο background script, παρακάμπτοντας εντελώς το Content Script και το CSP του.
Επομένως, αυτή είναι μια πολύ ισχυρή παράκαμψη.
Επιπλέον, αν ο πελάτης εγκαταστήσει μια κακόβουλη επέκταση, ακόμη και αν δεν επιτρέπεται να επικοινωνήσει με την ευάλωτη επέκταση, θα μπορούσε να εισάγει δεδομένα XSS σε μια επιτρεπόμενη ιστοσελίδα ή να εκμεταλλευτεί τα APIs WebRequest
ή DeclarativeNetRequest
για να χειριστεί αιτήματα σε έναν στοχευμένο τομέα, αλλάζοντας το αίτημα μιας σελίδας για ένα αρχείο JavaScript. (Σημειώστε ότι το CSP στη στοχευμένη σελίδα θα μπορούσε να αποτρέψει αυτές τις επιθέσεις). Αυτή η ιδέα προέρχεται από αυτή τη γραφή.
{% endhint %}
Περίληψη επικοινωνίας
Επέκταση <--> 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, ...
Where it's needed to mention the extension ID.
Web ↔︎ Επικοινωνία Σκηνικού Περιεχομένου
Τα περιβάλλοντα όπου λειτουργούν τα content scripts και όπου υπάρχουν οι σελίδες φιλοξενίας είναι χωρισμένα το ένα από το άλλο, εξασφαλίζοντας απομόνωση. Παρά αυτή την απομόνωση, και τα δύο έχουν τη δυνατότητα να αλληλεπιδρούν με το Document Object Model (DOM) της σελίδας, μια κοινή πηγή. Για να συμμετάσχει η σελίδα φιλοξενίας στην επικοινωνία με το content script, ή έμμεσα με την επέκταση μέσω του content script, απαιτείται να χρησιμοποιηθεί το DOM που είναι προσβάσιμο και από τις δύο πλευρές ως κανάλι επικοινωνίας.
Post Messages
{% code title="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);
{% endcode %}
{% code title="example.js" %}
document.getElementById("theButton").addEventListener("click", () => {
window.postMessage(
{type : "FROM_PAGE", text : "Hello from the webpage!"}, "*");
}, false);
{% endcode %}
Μια ασφαλής επικοινωνία Post Message θα πρέπει να ελέγχει την αυθεντικότητα του ληφθέντος μηνύματος, αυτό μπορεί να γίνει ελέγχοντας:
event.isTrusted
: Αυτό είναι True μόνο αν το γεγονός προκλήθηκε από ενέργεια του χρήστη- Το περιεχόμενο του script μπορεί να περιμένει ένα μήνυμα μόνο αν ο χρήστης εκτελέσει κάποια ενέργεια
- origin domain: μπορεί να περιμένει ένα μήνυμα μόνο από μια επιτρεπόμενη λίστα τομέων.
- Αν χρησιμοποιηθεί regex, να είστε πολύ προσεκτικοί
- Source:
received_message.source !== window
μπορεί να χρησιμοποιηθεί για να ελέγξει αν το μήνυμα ήταν από το ίδιο παράθυρο όπου το Content Script ακούει.
Οι προηγούμενοι έλεγχοι, ακόμη και αν εκτελούνται, θα μπορούσαν να είναι ευάλωτοι, οπότε ελέγξτε στην επόμενη σελίδα πιθανά bypasses Post Message:
{% content-ref url="../postmessage-vulnerabilities/" %} postmessage-vulnerabilities {% endcontent-ref %}
Iframe
Ένας άλλος πιθανός τρόπος επικοινωνίας μπορεί να είναι μέσω Iframe URLs, μπορείτε να βρείτε ένα παράδειγμα εδώ:
{% content-ref url="browext-xss-example.md" %} browext-xss-example.md {% endcontent-ref %}
DOM
Αυτό δεν είναι "ακριβώς" ένας τρόπος επικοινωνίας, αλλά το web και το content script θα έχουν πρόσβαση στο web DOM. Έτσι, αν το content script διαβάζει κάποιες πληροφορίες από αυτό, εμπιστευόμενο το web DOM, το web θα μπορούσε να τροποποιήσει αυτά τα δεδομένα (επειδή το web δεν θα πρέπει να εμπιστεύεται, ή επειδή το web είναι ευάλωτο σε XSS) και να συμβιβάσει το Content Script.
Μπορείτε επίσης να βρείτε ένα παράδειγμα DOM based XSS για να συμβιβάσετε μια επέκταση προγράμματος περιήγησης εδώ:
{% content-ref url="browext-xss-example.md" %} browext-xss-example.md {% endcontent-ref %}
Επικοινωνία 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()
θα ενεργοποιηθεί από προεπιλογή.
Ευαίσθητες Πληροφορίες στη Μνήμη/Κώδικα/Πρόχειρο
Εάν μια Επέκταση Περιηγητή αποθηκεύει ευαίσθητες πληροφορίες μέσα στη μνήμη της, αυτές θα μπορούσαν να εκχυθούν (ιδιαίτερα σε μηχανές Windows) και να αναζητηθούν για αυτές τις πληροφορίες.
Επομένως, η μνήμη της Επέκτασης Περιηγητή δεν θα πρέπει να θεωρείται ασφαλής και ευαίσθητες πληροφορίες όπως διαπιστευτήρια ή μνημονικές φράσεις δεν θα πρέπει να αποθηκεύονται.
Φυσικά, μην βάζετε ευαίσθητες πληροφορίες στον κώδικα, καθώς θα είναι δημόσιες.
Για να εκχύσετε μνήμη από τον περιηγητή μπορείτε να εκχύσετε τη μνήμη της διαδικασίας ή να πάτε στις ρυθμίσεις της επέκτασης του περιηγητή κάνοντας κλικ στο Inspect pop-up
-> Στην ενότητα Memory
-> Take a snapshot
και CTRL+F
για να αναζητήσετε μέσα στο στιγμιότυπο ευαίσθητες πληροφορίες.
Επιπλέον, εξαιρετικά ευαίσθητες πληροφορίες όπως μνημονικά κλειδιά ή κωδικοί πρόσβασης δεν θα πρέπει να επιτρέπεται να αντιγράφονται στο πρόχειρο (ή τουλάχιστον να αφαιρούνται από το πρόχειρο σε λίγα δευτερόλεπτα) γιατί τότε διαδικασίες που παρακολουθούν το πρόχειρο θα μπορούν να τις αποκτήσουν.
Φόρτωση μιας Επέκτασης στον Περιηγητή
- Κατεβάστε την Επέκταση Περιηγητή & αποσυμπιέστε την
- Πηγαίνετε στο
chrome://extensions/
και ενεργοποιήστε τη λειτουργίαDeveloper Mode
- Κάντε κλικ στο κουμπί
Load unpacked
Στο Firefox πηγαίνετε στο about:debugging#/runtime/this-firefox
και κάντε κλικ στο κουμπί Load Temporary Add-on
.
Λήψη του πηγαίου κώδικα από το κατάστημα
Ο πηγαίος κώδικας μιας επέκτασης Chrome μπορεί να αποκτηθεί μέσω διαφόρων μεθόδων. Παρακάτω παρατίθενται λεπτομερείς εξηγήσεις και οδηγίες για κάθε επιλογή.
Λήψη Επέκτασης ως ZIP μέσω Γραμμής Εντολών
Ο πηγαίος κώδικας μιας επέκτασης Chrome μπορεί να ληφθεί ως αρχείο ZIP χρησιμοποιώντας τη γραμμή εντολών. Αυτό περιλαμβάνει τη χρήση του curl
για να αποκτήσετε το αρχείο ZIP από μια συγκεκριμένη διεύθυνση URL και στη συνέχεια να εξαγάγετε τα περιεχόμενα του αρχείου ZIP σε έναν φάκελο. Ακολουθούν τα βήματα:
- Αντικαταστήστε το
"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, το οποίο είναι ένα ανοιχτού κώδικα έργο. Μπορεί να εγκατασταθεί από το Chrome Web Store. Ο πηγαίος κώδικας του viewer είναι διαθέσιμος στο GitHub repository.
Δείτε τον πηγαίο κώδικα της τοπικά εγκατεστημένης επέκτασης
Οι επεκτάσεις Chrome που έχουν εγκατασταθεί τοπικά μπορούν επίσης να επιθεωρηθούν. Να πώς:
- Αποκτήστε πρόσβαση στον τοπικό φάκελο προφίλ Chrome επισκεπτόμενοι το
chrome://version/
και εντοπίζοντας το πεδίο "Profile Path". - Πλοηγηθείτε στον υποφάκελο
Extensions/
εντός του φακέλου προφίλ. - Αυτός ο φάκελος περιέχει όλες τις εγκατεστημένες επεκτάσεις, συνήθως με τον πηγαίο κώδικα τους σε αναγνώσιμη μορφή.
Για να προσδιορίσετε τις επεκτάσεις, μπορείτε να αντιστοιχίσετε τα IDs τους σε ονόματα:
- Ενεργοποιήστε τη Λειτουργία Προγραμματιστή στη σελίδα
about:extensions
για να δείτε τα IDs κάθε επέκτασης. - Μέσα στον φάκελο κάθε επέκτασης, το αρχείο
manifest.json
περιέχει ένα αναγνώσιμο πεδίοname
, βοηθώντας σας να προσδιορίσετε την επέκταση.
Χρησιμοποιήστε ένα Αρχειοθέτη ή Αποσυμπιεστή
Πηγαίνετε στο Chrome Web Store και κατεβάστε την επέκταση. Το αρχείο θα έχει την επέκταση .crx
. Αλλάξτε την επέκταση του αρχείου από .crx
σε .zip
. Χρησιμοποιήστε οποιονδήποτε αρχειοθέτη (όπως WinRAR, 7-Zip, κ.λπ.) για να εξαγάγετε τα περιεχόμενα του αρχείου ZIP.
Χρησιμοποιήστε τη Λειτουργία Προγραμματιστή στο Chrome
Ανοίξτε το Chrome και πηγαίνετε στο chrome://extensions/
. Ενεργοποιήστε τη "Λειτουργία Προγραμματιστή" στην επάνω δεξιά γωνία. Κάντε κλικ στο "Φόρτωση αποσυμπιεσμένης επέκτασης...". Πλοηγηθείτε στον φάκελο της επέκτασής σας. Αυτό δεν κατεβάζει τον πηγαίο κώδικα, αλλά είναι χρήσιμο για την προβολή και την τροποποίηση του κώδικα μιας ήδη κατεβασμένης ή αναπτυγμένης επέκτασης.
Λίστα Ελέγχου Ασφαλείας
Ακόμα και αν οι Επεκτάσεις Περιηγητή έχουν μια περιορισμένη επιφάνεια επίθεσης, μερικές από αυτές μπορεί να περιέχουν ευπάθειες ή πιθανές βελτιώσεις ενίσχυσης. Οι παρακάτω είναι οι πιο κοινές:
- Περιορίστε όσο το δυνατόν περισσότερο τις ζητούμενες
permissions
- Περιορίστε όσο το δυνατόν περισσότερο τις
host_permissions
- Χρησιμοποιήστε μια ισχυρή
content_security_policy
- Περιορίστε όσο το δυνατόν περισσότερο το
externally_connectable
, αν δεν είναι απαραίτητο και δυνατό, μην το αφήνετε προεπιλεγμένο, καθορίστε{}
- Αν αναφέρεται εδώ URL ευάλωτο σε XSS ή σε κατάληψη, ένας επιτιθέμενος θα μπορεί να στέλνει μηνύματα στα background scripts απευθείας. Πολύ ισχυρή παράκαμψη.
- Περιορίστε όσο το δυνατόν περισσότερο τους
web_accessible_resources
, ακόμα και κενό αν είναι δυνατόν. - Αν οι
web_accessible_resources
δεν είναι κανένα, ελέγξτε για ClickJacking - Αν οποιαδήποτε επικοινωνία συμβαίνει από την επέκταση στη σελίδα web, ελέγξτε για XSS ευπάθειες που προκαλούνται στην επικοινωνία.
- Αν χρησιμοποιούνται Post Messages, ελέγξτε για ευπάθειες Post Message.
- Αν το Content Script έχει πρόσβαση σε λεπτομέρειες DOM, ελέγξτε ότι δεν εισάγουν XSS αν τροποποιηθούν από το web
- Δώστε ιδιαίτερη έμφαση αν αυτή η επικοινωνία εμπλέκεται επίσης στην επικοινωνία Content Script -> Background script
- Ευαίσθητες πληροφορίες δεν πρέπει να αποθηκεύονται μέσα στον κώδικα της Επέκτασης Περιηγητή
- Ευαίσθητες πληροφορίες δεν πρέπει να αποθηκεύονται μέσα στη μνήμη της Επέκτασης Περιηγητή
Εργαλεία
Tarnish
- Τραβά οποιαδήποτε επέκταση Chrome από έναν παρεχόμενο σύνδεσμο του Chrome webstore.
- manifest.json viewer: απλά εμφανίζει μια JSON-μορφοποιημένη έκδοση του manifest της επέκτασης.
- Ανάλυση Δακτυλικών Αποτυπωμάτων: Ανίχνευση web_accessible_resources και αυτόματη δημιουργία JavaScript δακτυλικών αποτυπωμάτων για επεκτάσεις Chrome.
- Πιθανή Ανάλυση Clickjacking: Ανίχνευση HTML σελίδων επεκτάσεων με τη ρύθμιση web_accessible_resources. Αυτές είναι πιθανώς ευάλωτες σε clickjacking ανάλογα με τον σκοπό των σελίδων.
- Viewer προειδοποιήσεων αδειών: που δείχνει μια λίστα με όλες τις προειδοποιήσεις προτροπής αδειών Chrome που θα εμφανιστούν όταν ένας χρήστης προσπαθήσει να εγκαταστήσει την επέκταση.
- Επικίνδυνες Λειτουργίες: δείχνει την τοποθεσία επικίνδυνων λειτουργιών που θα μπορούσαν να εκμεταλλευτούν από έναν επιτιθέμενο (π.χ. λειτουργίες όπως innerHTML, chrome.tabs.executeScript).
- Σημεία Εισόδου: δείχνει πού η επέκταση δέχεται είσοδο από χρήστη/εξωτερική είσοδο. Αυτό είναι χρήσιμο για την κατανόηση της επιφάνειας της επέκτασης και την αναζήτηση πιθανών σημείων για την αποστολή κακόβουλα κατασκευασμένων δεδομένων στην επέκταση.
- Και οι σάρωτες Επικίνδυνες Λειτουργίες και Σημεία Εισόδου έχουν τα εξής για τις παραγόμενες προειδοποιήσεις τους:
- Σχετικό απόσπασμα κώδικα και γραμμή που προκάλεσε την προειδοποίηση.
- Περιγραφή του ζητήματος.
- Ένα κουμπί "Δείτε το Αρχείο" για να δείτε το πλήρες αρχείο πηγαίου κώδικα που περιέχει τον κώδικα.
- Η διαδρομή του αρχείου που προειδοποιήθηκε.
- Η πλήρης URI της επέκτασης Chrome του αρχείου που προειδοποιήθηκε.
- Ο τύπος του αρχείου, όπως σενάριο Background Page, Content Script, Browser Action, κ.λπ.
- Αν η ευάλωτη γραμμή είναι σε ένα αρχείο JavaScript, οι διαδρομές όλων των σελίδων όπου περιλαμβάνεται καθώς και ο τύπος αυτών των σελίδων, και η κατάσταση web_accessible_resource.
- Αναλυτής Πολιτικής Ασφαλείας Περιεχομένου (CSP) και ελεγκτής παράκαμψης: Αυτό θα επισημάνει αδυναμίες στην CSP της επέκτασής σας και θα φωτίσει επίσης τυχόν πιθανές μεθόδους για να παρακάμψετε την CSP σας λόγω λευκωμένων CDNs, κ.λπ.
- Γνωστές Ευάλωτες Βιβλιοθήκες: Αυτό χρησιμοποιεί Retire.js για να ελέγξει για οποιαδήποτε χρήση γνωστών ευάλωτων βιβλιοθηκών JavaScript.
- Κατεβάστε την επέκταση και μορφοποιημένες εκδόσεις.
- Κατεβάστε την αρχική επέκταση.
- Κατεβάστε μια όμορφα μορφοποιημένη έκδοση της επέκτασης (αυτόματη μορφοποίηση HTML και JavaScript).
- Αυτόματη αποθήκευση αποτελεσμάτων σάρωσης, η εκτέλεση μιας σάρωσης επέκτασης θα διαρκέσει αρκετό χρόνο την πρώτη φορά που θα την εκτελέσετε. Ωστόσο, τη δεύτερη φορά, εφόσον η επέκταση δεν έχει ενημερωθεί, θα είναι σχεδόν άμεση λόγω της αποθήκευσης των αποτελεσμάτων.
- Συνδέσιμες διευθύνσεις URL αναφορών, εύκολα συνδέστε κάποιον άλλο σε μια αναφορά επέκτασης που δημιουργήθηκε από το tarnish.
Neto
Το έργο Neto είναι ένα πακέτο Python 3 που έχει σχεδιαστεί για να αναλύει και να αποκαλύπτει κρυφές δυνατότητες των πρόσθετων και επεκτάσεων προγράμματος περιήγησης για γνωστούς περιηγητές όπως ο Firefox και ο Chrome. Αυτοματοποιεί τη διαδικασία αποσυμπίεσης των πακεταρισμένων αρχείων για να εξαγάγει αυτές τις δυνατότητες από σχετικούς πόρους σε μια επέκταση όπως το manifest.json
, τους φακέλους τοπικοποίησης ή τα αρχεία πηγαίου κώδικα JavaScript και HTML.
Αναφορές
- Ευχαριστώ τον @naivenom για τη βοήθεια με αυτή τη μεθοδολογία
- 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
{% hint style="success" %}
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Support HackTricks
- Check the subscription plans!
- Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.