Translated ['src/pentesting-web/hacking-with-cookies/README.md'] to el

This commit is contained in:
Translator 2025-05-18 03:05:40 +00:00
parent 443b4c7daf
commit f6941c93de
2 changed files with 163 additions and 141 deletions

View File

@ -16,11 +16,11 @@
### Path ### Path
Ένας συγκεκριμένος διαδρομή URL που πρέπει να είναι παρούσα στο ζητούμενο URL για να σταλεί η κεφαλίδα `Cookie` υποδεικνύεται από το χαρακτηριστικό `Path`. Αυτό το χαρακτηριστικό θεωρεί τον χαρακτήρα `/` ως διαχωριστικό καταλόγου, επιτρέποντας αντιστοιχίες σε υποκαταλόγους επίσης. Ένας συγκεκριμένος διαδρομή URL που πρέπει να είναι παρών στο ζητούμενο URL για να σταλεί η κεφαλίδα `Cookie` υποδεικνύεται από το χαρακτηριστικό `Path`. Αυτό το χαρακτηριστικό θεωρεί τον χαρακτήρα `/` ως διαχωριστικό καταλόγου, επιτρέποντας αντιστοιχίες και σε υποκαταλόγους.
### Ordering Rules ### Ordering Rules
Όταν δύο cookies φέρουν το ίδιο όνομα, το επιλεγμένο για αποστολή βασίζεται σε: Όταν δύο cookies φέρουν το ίδιο όνομα, το cookie που επιλέγεται για αποστολή βασίζεται σε:
- Το cookie που ταιριάζει με τη μεγαλύτερη διαδρομή στο ζητούμενο URL. - Το cookie που ταιριάζει με τη μεγαλύτερη διαδρομή στο ζητούμενο URL.
- Το πιο πρόσφατα ρυθμισμένο cookie αν οι διαδρομές είναι ταυτόσημες. - Το πιο πρόσφατα ρυθμισμένο cookie αν οι διαδρομές είναι ταυτόσημες.
@ -32,7 +32,7 @@
- **Lax**: Επιτρέπει στο cookie να αποστέλλεται με αιτήματα GET που ξεκινούν από τρίτους ιστότοπους. - **Lax**: Επιτρέπει στο cookie να αποστέλλεται με αιτήματα GET που ξεκινούν από τρίτους ιστότοπους.
- **None**: Επιτρέπει στο cookie να αποστέλλεται από οποιονδήποτε τρίτο τομέα. - **None**: Επιτρέπει στο cookie να αποστέλλεται από οποιονδήποτε τρίτο τομέα.
Θυμηθείτε, ενώ ρυθμίζετε cookies, η κατανόηση αυτών των χαρακτηριστικών μπορεί να βοηθήσει να διασφαλιστεί ότι συμπεριφέρονται όπως αναμένεται σε διάφορα σενάρια. Θυμηθείτε, ενώ ρυθμίζετε τα cookies, η κατανόηση αυτών των χαρακτηριστικών μπορεί να βοηθήσει να διασφαλιστεί ότι συμπεριφέρονται όπως αναμένεται σε διάφορα σενάρια.
| **Request Type** | **Example Code** | **Cookies Sent When** | | **Request Type** | **Example Code** | **Cookies Sent When** |
| ---------------- | ---------------------------------- | --------------------- | | ---------------- | ---------------------------------- | --------------------- |
@ -48,7 +48,7 @@ Table from [Invicti](https://www.netsparker.com/blog/web-security/same-site-cook
Ένα cookie με το χαρακτηριστικό _**SameSite**_ θα **μειώσει τις επιθέσεις CSRF** όπου απαιτείται μια συνδεδεμένη συνεδρία. Ένα cookie με το χαρακτηριστικό _**SameSite**_ θα **μειώσει τις επιθέσεις CSRF** όπου απαιτείται μια συνδεδεμένη συνεδρία.
**\*Σημειώστε ότι από το Chrome80 (φλεβ/2019) η προεπιλεγμένη συμπεριφορά ενός cookie χωρίς χαρακτηριστικό cookie samesite** **θα είναι lax** ([https://www.troyhunt.com/promiscuous-cookies-and-their-impending-death-via-the-samesite-policy/](https://www.troyhunt.com/promiscuous-cookies-and-their-impending-death-via-the-samesite-policy/)).\ **\*Σημειώστε ότι από το Chrome80 (φλεβ/2019) η προεπιλεγμένη συμπεριφορά ενός cookie χωρίς χαρακτηριστικό cookie samesite** **θα είναι lax** ([https://www.troyhunt.com/promiscuous-cookies-and-their-impending-death-via-the-samesite-policy/](https://www.troyhunt.com/promiscuous-cookies-and-their-impending-death-via-the-samesite-policy/)).\
Σημειώστε ότι προσωρινά, μετά την εφαρμογή αυτής της αλλαγής, τα **cookies χωρίς πολιτική SameSite** **στο Chrome θα θεωρούνται** **ως None** κατά τη διάρκεια των **πρώτων 2 λεπτών και στη συνέχεια ως Lax για αιτήματα POST διασύνδεσης κορυφής.** Σημειώστε ότι προσωρινά, μετά την εφαρμογή αυτής της αλλαγής, τα **cookies χωρίς πολιτική SameSite** **στο Chrome θα θεωρούνται** **None** κατά τη διάρκεια των **πρώτων 2 λεπτών και στη συνέχεια ως Lax για αιτήματα POST διασύνδεσης κορυφαίου επιπέδου.**
## Cookies Flags ## Cookies Flags
@ -58,11 +58,11 @@ Table from [Invicti](https://www.netsparker.com/blog/web-security/same-site-cook
#### **Bypasses** #### **Bypasses**
- Αν η σελίδα **στέλνει τα cookies ως απάντηση** σε αιτήματα (για παράδειγμα σε μια σελίδα **PHPinfo**), είναι δυνατόν να καταχραστεί το XSS για να στείλει ένα αίτημα σε αυτή τη σελίδα και να **κλέψει τα cookies** από την απάντηση (ελέγξτε ένα παράδειγμα στο [https://hackcommander.github.io/posts/2022/11/12/bypass-httponly-via-php-info-page/](https://hackcommander.github.io/posts/2022/11/12/bypass-httponly-via-php-info-page/). - Αν η σελίδα **στέλνει τα cookies ως απάντηση** σε αιτήματα (για παράδειγμα σε μια σελίδα **PHPinfo**), είναι δυνατόν να εκμεταλλευτείτε το XSS για να στείλετε ένα αίτημα σε αυτή τη σελίδα και να **κλέψετε τα cookies** από την απάντηση (ελέγξτε ένα παράδειγμα στο [https://blog.hackcommander.com/posts/2022/11/12/bypass-httponly-via-php-info-page/](https://blog.hackcommander.com/posts/2022/11/12/bypass-httponly-via-php-info-page/)).
- Αυτό μπορεί να παρακαμφθεί με **TRACE** **HTTP** αιτήματα καθώς η απάντηση από τον διακομιστή (αν αυτή η μέθοδος HTTP είναι διαθέσιμη) θα αντικατοπτρίζει τα cookies που στάλθηκαν. Αυτή η τεχνική ονομάζεται **Cross-Site Tracking**. - Αυτό μπορεί να παρακαμφθεί με **TRACE** **HTTP** αιτήματα καθώς η απάντηση από τον διακομιστή (αν αυτή η μέθοδος HTTP είναι διαθέσιμη) θα αντικατοπτρίζει τα cookies που στάλθηκαν. Αυτή η τεχνική ονομάζεται **Cross-Site Tracking**.
- Αυτή η τεχνική αποφεύγεται από **σύγχρονους περιηγητές με το να μην επιτρέπουν την αποστολή ενός TRACE** αιτήματος από JS. Ωστόσο, έχουν βρεθεί ορισμένες παρακάμψεις σε συγκεκριμένο λογισμικό όπως η αποστολή `\r\nTRACE` αντί για `TRACE` στο IE6.0 SP2. - Αυτή η τεχνική αποφεύγεται από **σύγχρονους περιηγητές με το να μην επιτρέπουν την αποστολή ενός TRACE** αιτήματος από JS. Ωστόσο, έχουν βρεθεί ορισμένες παρακάμψεις σε συγκεκριμένο λογισμικό όπως η αποστολή `\r\nTRACE` αντί για `TRACE` στο IE6.0 SP2.
- Ένας άλλος τρόπος είναι η εκμετάλλευση ευπαθειών μηδενικής ημέρας στους περιηγητές. - Ένας άλλος τρόπος είναι η εκμετάλλευση ευπαθειών μηδενικής ημέρας στους περιηγητές.
- Είναι δυνατόν να **επικαλύψετε τα HttpOnly cookies** εκτελώντας μια επίθεση overflow Cookie Jar: - Είναι δυνατόν να **επικαλύψετε τα HttpOnly cookies** εκτελώντας μια επίθεση Cookie Jar overflow:
{{#ref}} {{#ref}}
cookie-jar-overflow.md cookie-jar-overflow.md
@ -72,28 +72,28 @@ cookie-jar-overflow.md
### Secure ### Secure
Η αίτηση θα **στείλει** το cookie μόνο σε μια HTTP αίτηση εάν η αίτηση μεταδίδεται μέσω ενός ασφαλούς καναλιού (συνήθως **HTTPS**). Η αίτηση θα **στείλει** το cookie σε ένα HTTP αίτημα μόνο εάν η αίτηση μεταδίδεται μέσω ενός ασφαλούς καναλιού (συνήθως **HTTPS**).
## Cookies Prefixes ## Cookies Prefixes
Τα cookies που προγραμματίζονται με `__Secure-` απαιτείται να ρυθμιστούν παράλληλα με τη σημαία `secure` από σελίδες που είναι ασφαλισμένες με HTTPS. Τα cookies που έχουν πρόθεμα `__Secure-` απαιτείται να ρυθμιστούν μαζί με τη σημαία `secure` από σελίδες που είναι ασφαλισμένες μέσω HTTPS.
Για τα cookies που προγραμματίζονται με `__Host-`, πρέπει να πληρούνται αρκετές προϋποθέσεις: Για τα cookies που έχουν πρόθεμα `__Host-`, πρέπει να πληρούνται αρκετές προϋποθέσεις:
- Πρέπει να ρυθμιστούν με τη σημαία `secure`. - Πρέπει να ρυθμιστούν με τη σημαία `secure`.
- Πρέπει να προέρχονται από μια σελίδα ασφαλισμένη με HTTPS. - Πρέπει να προέρχονται από μια σελίδα ασφαλισμένη μέσω HTTPS.
- Απαγορεύεται να καθορίζουν ένα domain, αποτρέποντας τη μετάδοσή τους σε υποτομείς. - Απαγορεύεται να καθορίζουν ένα domain, αποτρέποντας τη μετάδοσή τους σε υποτομείς.
- Η διαδρομή για αυτά τα cookies πρέπει να ρυθμιστεί σε `/`. - Η διαδρομή για αυτά τα cookies πρέπει να ρυθμιστεί σε `/`.
Είναι σημαντικό να σημειωθεί ότι τα cookies που προγραμματίζονται με `__Host-` δεν επιτρέπεται να αποστέλλονται σε υπερτομείς ή υποτομείς. Αυτός ο περιορισμός βοηθά στην απομόνωση των cookies εφαρμογής. Έτσι, η χρήση του προθέματος `__Host-` για όλα τα cookies εφαρμογής μπορεί να θεωρηθεί καλή πρακτική για την ενίσχυση της ασφάλειας και της απομόνωσης. Είναι σημαντικό να σημειωθεί ότι τα cookies που έχουν πρόθεμα `__Host-` δεν επιτρέπεται να αποστέλλονται σε υπερτομείς ή υποτομείς. Αυτός ο περιορισμός βοηθά στην απομόνωση των cookies εφαρμογής. Έτσι, η χρήση του προθέματος `__Host-` για όλα τα cookies εφαρμογής μπορεί να θεωρηθεί καλή πρακτική για την ενίσχυση της ασφάλειας και της απομόνωσης.
### Overwriting cookies ### Overwriting cookies
Έτσι, μία από τις προστασίες των cookies που προγραμματίζονται με `__Host-` είναι να αποτρέπουν την επικάλυψή τους από υποτομείς. Αποτρέποντας για παράδειγμα [**Cookie Tossing attacks**](cookie-tossing.md). Στην ομιλία [**Cookie Crumbles: Unveiling Web Session Integrity Vulnerabilities**](https://www.youtube.com/watch?v=F_wAzF4a7Xg) ([**paper**](https://www.usenix.org/system/files/usenixsecurity23-squarcina.pdf)) παρουσιάζεται ότι ήταν δυνατόν να ρυθμιστούν cookies με πρόθεμα \_\_HOST- από υποτομέα, παραπλανώντας τον αναλυτή, για παράδειγμα, προσθέτοντας "=" στην αρχή ή στην αρχή και στο τέλος...: Έτσι, μία από τις προστασίες των cookies με πρόθεμα `__Host-` είναι να αποτρέπουν την επικάλυψή τους από υποτομείς. Αποτρέποντας για παράδειγμα [**Cookie Tossing attacks**](cookie-tossing.md). Στην ομιλία [**Cookie Crumbles: Unveiling Web Session Integrity Vulnerabilities**](https://www.youtube.com/watch?v=F_wAzF4a7Xg) ([**paper**](https://www.usenix.org/system/files/usenixsecurity23-squarcina.pdf)) παρουσιάζεται ότι ήταν δυνατόν να ρυθμιστούν cookies με πρόθεμα \_\_HOST- από υποτομέα, παραπλανώντας τον αναλυτή, για παράδειγμα, προσθέτοντας "=" στην αρχή ή στην αρχή και στο τέλος...:
<figure><img src="../../images/image (6) (1) (1) (1) (1).png" alt=""><figcaption></figcaption></figure> <figure><img src="../../images/image (6) (1) (1) (1) (1).png" alt=""><figcaption></figcaption></figure>
Ή σε PHP ήταν δυνατόν να προστεθούν **άλλοι χαρακτήρες στην αρχή** του ονόματος cookie που θα **αντικαθίσταντο με χαρακτήρες υπογράμμισης**, επιτρέποντας την επικάλυψη των cookies `__HOST-`: Ή σε PHP ήταν δυνατόν να προστεθούν **άλλοι χαρακτήρες στην αρχή** του ονόματος cookie που θα **αντικαθίσταντο με χαρακτήρες υπογράμμισης**, επιτρέποντας την επικάλυψη των `__HOST-` cookies:
<figure><img src="../../images/image (7) (1) (1) (1) (1).png" alt="" width="373"><figcaption></figcaption></figure> <figure><img src="../../images/image (7) (1) (1) (1) (1).png" alt="" width="373"><figcaption></figcaption></figure>
@ -103,7 +103,7 @@ cookie-jar-overflow.md
### Decoding and Manipulating Cookies ### Decoding and Manipulating Cookies
Τα ευαίσθητα δεδομένα που ενσωματώνονται σε cookies θα πρέπει πάντα να εξετάζονται προσεκτικά. Τα cookies που είναι κωδικοποιημένα σε Base64 ή παρόμοιες μορφές μπορούν συχνά να αποκωδικοποιηθούν. Αυτή η ευπάθεια επιτρέπει στους επιτιθέμενους να τροποποιούν το περιεχόμενο του cookie και να προσποιούνται άλλους χρήστες κωδικοποιώντας τα τροποποιημένα δεδομένα πίσω στο cookie. Τα ευαίσθητα δεδομένα που ενσωματώνονται σε cookies θα πρέπει πάντα να εξετάζονται προσεκτικά. Τα cookies που είναι κωδικοποιημένα σε Base64 ή παρόμοιες μορφές μπορούν συχνά να αποκωδικοποιηθούν. Αυτή η ευπάθεια επιτρέπει στους επιτιθέμενους να τροποποιήσουν το περιεχόμενο του cookie και να προσποιηθούν άλλους χρήστες κωδικοποιώντας τα τροποποιημένα δεδομένα πίσω στο cookie.
### Session Hijacking ### Session Hijacking
@ -111,9 +111,9 @@ cookie-jar-overflow.md
### Session Fixation ### Session Fixation
Σε αυτό το σενάριο, ένας επιτιθέμενος παραπλανεί ένα θύμα να χρησιμοποιήσει ένα συγκεκριμένο cookie για να συνδεθεί. Αν η εφαρμογή δεν αναθέσει ένα νέο cookie κατά την είσοδο, ο επιτιθέμενος, που κατέχει το αρχικό cookie, μπορεί να προσποιηθεί το θύμα. Αυτή η τεχνική βασίζεται στο γεγονός ότι το θύμα συνδέεται με ένα cookie που παρέχεται από τον επιτιθέμενο. Σε αυτό το σενάριο, ένας επιτιθέμενος παραπλανεί ένα θύμα να χρησιμοποιήσει ένα συγκεκριμένο cookie για να συνδεθεί. Αν η εφαρμογή δεν αναθέσει ένα νέο cookie κατά την είσοδο, ο επιτιθέμενος, που κατέχει το αρχικό cookie, μπορεί να προσποιηθεί το θύμα. Αυτή η τεχνική βασίζεται στο να συνδεθεί το θύμα με ένα cookie που παρέχεται από τον επιτιθέμενο.
Αν βρείτε ένα **XSS σε υποτομέα** ή ελέγχετε έναν υποτομέα, διαβάστε: Αν βρείτε ένα **XSS σε έναν υποτομέα** ή ελέγχετε έναν υποτομέα, διαβάστε:
{{#ref}} {{#ref}}
cookie-tossing.md cookie-tossing.md
@ -123,7 +123,7 @@ cookie-tossing.md
Εδώ, ο επιτιθέμενος πείθει το θύμα να χρησιμοποιήσει το cookie συνεδρίας του επιτιθέμενου. Το θύμα, πιστεύοντας ότι είναι συνδεδεμένο στον δικό του λογαριασμό, θα εκτελέσει ακούσια ενέργειες στο πλαίσιο του λογαριασμού του επιτιθέμενου. Εδώ, ο επιτιθέμενος πείθει το θύμα να χρησιμοποιήσει το cookie συνεδρίας του επιτιθέμενου. Το θύμα, πιστεύοντας ότι είναι συνδεδεμένο στον δικό του λογαριασμό, θα εκτελέσει ακούσια ενέργειες στο πλαίσιο του λογαριασμού του επιτιθέμενου.
Αν βρείτε ένα **XSS σε υποτομέα** ή ελέγχετε έναν υποτομέα, διαβάστε: Αν βρείτε ένα **XSS σε έναν υποτομέα** ή ελέγχετε έναν υποτομέα, διαβάστε:
{{#ref}} {{#ref}}
cookie-tossing.md cookie-tossing.md
@ -147,7 +147,7 @@ document.cookie = "a=v1"
document.cookie = "=test value;" // Setting an empty named cookie document.cookie = "=test value;" // Setting an empty named cookie
document.cookie = "b=v2" document.cookie = "b=v2"
``` ```
Το αποτέλεσμα στην κεφαλίδα cookie που στάλθηκε είναι `a=v1; test value; b=v2;`. Ενδιαφέρον είναι ότι αυτό επιτρέπει τη χειραγώγηση των cookies αν έχει οριστεί ένα cookie με κενό όνομα, ελέγχοντας δυνητικά άλλα cookies ορίζοντας το κενό cookie σε μια συγκεκριμένη τιμή: Το αποτέλεσμα στην κεφαλίδα cookie που αποστέλλεται είναι `a=v1; test value; b=v2;`. Ενδιαφέρον είναι ότι αυτό επιτρέπει τη χειραγώγηση των cookies αν έχει οριστεί ένα cookie με κενό όνομα, ελέγχοντας δυνητικά άλλα cookies ορίζοντας το κενό cookie σε μια συγκεκριμένη τιμή:
```js ```js
function setCookie(name, value) { function setCookie(name, value) {
document.cookie = `${name}=${value}` document.cookie = `${name}=${value}`
@ -157,7 +157,7 @@ setCookie("", "a=b") // Setting the empty cookie modifies another cookie's value
``` ```
Αυτό οδηγεί στο να στέλνει ο περιηγητής μια κεφαλίδα cookie που ερμηνεύεται από κάθε διακομιστή ιστού ως ένα cookie με όνομα `a` και τιμή `b`. Αυτό οδηγεί στο να στέλνει ο περιηγητής μια κεφαλίδα cookie που ερμηνεύεται από κάθε διακομιστή ιστού ως ένα cookie με όνομα `a` και τιμή `b`.
#### Chrome Bug: Πρόβλημα Κωδικών Υποκαταστάσεων Unicode #### Chrome Bug: Πρόβλημα Κωδικών Υποκατάστασης Unicode
Στο Chrome, αν ένας κωδικός υποκατάστασης Unicode είναι μέρος ενός σετ cookie, το `document.cookie` γίνεται κατεστραμμένο, επιστρέφοντας μια κενή συμβολοσειρά στη συνέχεια: Στο Chrome, αν ένας κωδικός υποκατάστασης Unicode είναι μέρος ενός σετ cookie, το `document.cookie` γίνεται κατεστραμμένο, επιστρέφοντας μια κενή συμβολοσειρά στη συνέχεια:
```js ```js
@ -167,11 +167,11 @@ document.cookie = "\ud800=meep"
#### Cookie Smuggling λόγω προβλημάτων ανάλυσης #### Cookie Smuggling λόγω προβλημάτων ανάλυσης
(Δείτε περισσότερες λεπτομέρειες στην[πρωτότυπη έρευνα](https://blog.ankursundara.com/cookie-bugs/)) Πολλοί διακομιστές ιστού, συμπεριλαμβανομένων αυτών από Java (Jetty, TomCat, Undertow) και Python (Zope, cherrypy, web.py, aiohttp, bottle, webob), χειρίζονται λανθασμένα τις συμβολοσειρές cookie λόγω παρωχημένης υποστήριξης RFC2965. Διαβάζουν μια τιμή cookie με διπλά εισαγωγικά ως μία μόνο τιμή, ακόμη και αν περιλαμβάνει ερωτηματικά, τα οποία κανονικά θα έπρεπε να διαχωρίζουν τα ζεύγη κλειδιού-τιμής: (Δείτε περισσότερες λεπτομέρειες στην [πρωτότυπη έρευνα](https://blog.ankursundara.com/cookie-bugs/)) Πολλοί web servers, συμπεριλαμβανομένων αυτών από Java (Jetty, TomCat, Undertow) και Python (Zope, cherrypy, web.py, aiohttp, bottle, webob), χειρίζονται λανθασμένα τις συμβολοσειρές cookie λόγω παρωχημένης υποστήριξης RFC2965. Διαβάζουν μια διπλά εισαγωγική τιμή cookie ως μία μόνο τιμή, ακόμη και αν περιλαμβάνει ερωτηματικά, τα οποία κανονικά θα έπρεπε να διαχωρίζουν τα ζεύγη κλειδιού-τιμής:
``` ```
RENDER_TEXT="hello world; JSESSIONID=13371337; ASDF=end"; RENDER_TEXT="hello world; JSESSIONID=13371337; ASDF=end";
``` ```
#### Ευπάθειες Εισαγωγής Cookie #### Ευπάθειες Εισαγωγής Cookies
(Δείτε περισσότερες λεπτομέρειες στην [πρωτότυπη έρευνα](https://blog.ankursundara.com/cookie-bugs/)) Η λανθασμένη ανάλυση των cookies από τους διακομιστές, ιδίως τους Undertow, Zope και αυτούς που χρησιμοποιούν το `http.cookie.SimpleCookie` και `http.cookie.BaseCookie` της Python, δημιουργεί ευκαιρίες για επιθέσεις εισαγωγής cookies. Αυτοί οι διακομιστές αποτυγχάνουν να καθορίσουν σωστά την αρχή νέων cookies, επιτρέποντας στους επιτιθέμενους να παραποιήσουν cookies: (Δείτε περισσότερες λεπτομέρειες στην [πρωτότυπη έρευνα](https://blog.ankursundara.com/cookie-bugs/)) Η λανθασμένη ανάλυση των cookies από τους διακομιστές, ιδίως τους Undertow, Zope και αυτούς που χρησιμοποιούν το `http.cookie.SimpleCookie` και `http.cookie.BaseCookie` της Python, δημιουργεί ευκαιρίες για επιθέσεις εισαγωγής cookies. Αυτοί οι διακομιστές αποτυγχάνουν να καθορίσουν σωστά την αρχή νέων cookies, επιτρέποντας στους επιτιθέμενους να παραποιήσουν cookies:
@ -179,7 +179,7 @@ RENDER_TEXT="hello world; JSESSIONID=13371337; ASDF=end";
- Ο Zope αναζητά μια κόμμα για να αρχίσει την ανάλυση του επόμενου cookie. - Ο Zope αναζητά μια κόμμα για να αρχίσει την ανάλυση του επόμενου cookie.
- Οι κλάσεις cookie της Python αρχίζουν την ανάλυση σε έναν χαρακτήρα κενό. - Οι κλάσεις cookie της Python αρχίζουν την ανάλυση σε έναν χαρακτήρα κενό.
Αυτή η ευπάθεια είναι ιδιαίτερα επικίνδυνη σε διαδικτυακές εφαρμογές που βασίζονται στην προστασία CSRF μέσω cookies, καθώς επιτρέπει στους επιτιθέμενους να εισάγουν παραποιημένα cookies CSRF-token, πιθανώς παρακάμπτοντας τα μέτρα ασφαλείας. Το πρόβλημα επιδεινώνεται από την επεξεργασία των διπλών ονομάτων cookie από την Python, όπου η τελευταία εμφάνιση υπερισχύει των προηγούμενων. Επίσης, εγείρει ανησυχίες για τα cookies `__Secure-` και `__Host-` σε ανασφαλείς συνθήκες και θα μπορούσε να οδηγήσει σε παρακάμψεις εξουσιοδότησης όταν τα cookies μεταφέρονται σε διακομιστές backend που είναι ευάλωτοι σε παραποίηση. Αυτή η ευπάθεια είναι ιδιαίτερα επικίνδυνη σε διαδικτυακές εφαρμογές που βασίζονται στην προστασία CSRF μέσω cookies, καθώς επιτρέπει στους επιτιθέμενους να εισάγουν παραποιημένα cookies CSRF-token, ενδεχομένως παρακάμπτοντας τα μέτρα ασφαλείας. Το πρόβλημα επιδεινώνεται από την επεξεργασία των διπλών ονομάτων cookies από την Python, όπου η τελευταία εμφάνιση υπερκαλύπτει τις προηγούμενες. Επίσης, εγείρει ανησυχίες για τα cookies `__Secure-` και `__Host-` σε ανασφαλείς περιβάλλοντες και θα μπορούσε να οδηγήσει σε παρακάμψεις εξουσιοδότησης όταν τα cookies μεταφέρονται σε διακομιστές backend που είναι ευάλωτοι σε παραποίηση.
### Cookies $version ### Cookies $version
@ -189,15 +189,15 @@ RENDER_TEXT="hello world; JSESSIONID=13371337; ASDF=end";
#### Επίθεση Sandwich Cookie #### Επίθεση Sandwich Cookie
Σύμφωνα με [**αυτή την ανάρτηση**](https://portswigger.net/research/stealing-httponly-cookies-with-the-cookie-sandwich-technique), είναι δυνατό να χρησιμοποιηθεί η τεχνική sandwich cookie για να κλέψετε HttpOnly cookies. Αυτές είναι οι απαιτήσεις και τα βήματα: Σύμφωνα με [**αυτή την ανάρτηση**](https://portswigger.net/research/stealing-httponly-cookies-with-the-cookie-sandwich-technique), είναι δυνατό να χρησιμοποιηθεί η τεχνική sandwich cookie για να κλέψει HttpOnly cookies. Αυτές είναι οι απαιτήσεις και τα βήματα:
- Βρείτε ένα μέρος όπου ένα φαινομενικά άχρηστο **cookie ανακλάται στην απάντηση** - Βρείτε ένα μέρος όπου ένα φαινομενικά άχρηστο **cookie ανακλάται στην απόκριση**
- **Δημιουργήστε ένα cookie που ονομάζεται `$Version`** με τιμή `1` (μπορείτε να το κάνετε αυτό σε μια επίθεση XSS από JS) με μια πιο συγκεκριμένη διαδρομή ώστε να πάρει την αρχική θέση (ορισμένα πλαίσια όπως η Python δεν χρειάζονται αυτό το βήμα) - **Δημιουργήστε ένα cookie που ονομάζεται `$Version`** με τιμή `1` (μπορείτε να το κάνετε αυτό σε μια επίθεση XSS από JS) με μια πιο συγκεκριμένη διαδρομή ώστε να πάρει την αρχική θέση (ορισμένα πλαίσια όπως η Python δεν χρειάζονται αυτό το βήμα)
- **Δημιουργήστε το cookie που ανακλάται** με μια τιμή που αφήνει **ανοιχτές διπλές εισαγωγές** και με μια συγκεκριμένη διαδρομή ώστε να τοποθετηθεί στη βάση δεδομένων cookie μετά το προηγούμενο (`$Version`) - **Δημιουργήστε το cookie που ανακλάται** με μια τιμή που αφήνει **ανοιχτές διπλές εισαγωγές** και με μια συγκεκριμένη διαδρομή ώστε να τοποθετηθεί στη βάση δεδομένων cookies μετά το προηγούμενο (`$Version`)
- Στη συνέχεια, το νόμιμο cookie θα πάει επόμενο στη σειρά - Στη συνέχεια, το νόμιμο cookie θα πάει επόμενο στη σειρά
- **Δημιουργήστε ένα ψεύτικο cookie που κλείνει τις διπλές εισαγωγές** μέσα στην τιμή του - **Δημιουργήστε ένα ψεύτικο cookie που κλείνει τις διπλές εισαγωγές** μέσα στην τιμή του
Με αυτόν τον τρόπο, το cookie του θύματος παγιδεύεται μέσα στο νέο cookie έκδοσης 1 και θα ανακλάται όποτε ανακλάται. π.χ. από την ανάρτηση: Με αυτόν τον τρόπο, το cookie του θύματος παγιδεύεται μέσα στο νέο cookie έκδοση 1 και θα ανακλάται όποτε ανακλάται.
```javascript ```javascript
document.cookie = `$Version=1;`; document.cookie = `$Version=1;`;
document.cookie = `param1="start`; document.cookie = `param1="start`;
@ -212,18 +212,18 @@ document.cookie = `param2=end";`;
#### Bypassing value analysis with quoted-string encoding #### Bypassing value analysis with quoted-string encoding
Αυτή η ανάλυση υποδεικνύει την αποσυμπίεση των τιμών που έχουν διαφύγει μέσα στα cookies, έτσι ώστε το "\a" να γίνεται "a". Αυτό μπορεί να είναι χρήσιμο για την παράκαμψη των WAFS όπως: Αυτή η ανάλυση υποδεικνύει την αποσυμπίεση των εκφρασμένων τιμών μέσα στα cookies, έτσι ώστε το "\a" να γίνεται "a". Αυτό μπορεί να είναι χρήσιμο για την παράκαμψη των WAFS όπως:
- `eval('test') => forbidden` - `eval('test') => forbidden`
- `"\e\v\a\l\(\'\t\e\s\t\'\)" => allowed` - `"\e\v\a\l\(\'\t\e\s\t\'\)" => allowed`
#### Bypassing cookie-name blocklists #### Bypassing cookie-name blocklists
Στο RFC2109 αναφέρεται ότι μια **κόμμα μπορεί να χρησιμοποιηθεί ως διαχωριστικό μεταξύ των τιμών των cookies**. Επίσης, είναι δυνατό να προστεθούν **κενά και ταμπς πριν και μετά το ίσον**. Επομένως, ένα cookie όπως `$Version=1; foo=bar, abc = qux` δεν παράγει το cookie `"foo":"bar, admin = qux"` αλλά τα cookies `foo":"bar"` και `"admin":"qux"`. Παρατηρήστε πώς παράγονται 2 cookies και πώς το admin έχει αφαιρεθεί το κενό πριν και μετά το ίσον. Στο RFC2109 αναφέρεται ότι μια **κόμμα μπορεί να χρησιμοποιηθεί ως διαχωριστικό μεταξύ των τιμών των cookies**. Επίσης, είναι δυνατή η προσθήκη **κενών και ταμπών πριν και μετά το ίσον**. Επομένως, ένα cookie όπως `$Version=1; foo=bar, abc = qux` δεν παράγει το cookie `"foo":"bar, admin = qux"` αλλά τα cookies `foo":"bar"` και `"admin":"qux"`. Παρατηρήστε πώς παράγονται 2 cookies και πώς το admin έχει αφαιρεθεί το κενό πριν και μετά το ίσον.
#### Bypassing value analysis with cookie splitting #### Bypassing value analysis with cookie splitting
Τέλος, διάφορες πίσω πόρτες θα συνδυάζουν σε μια συμβολοσειρά διαφορετικά cookies που έχουν περαστεί σε διαφορετικούς επικεφαλίδες cookies όπως σε: Τέλος, διάφορες πίσω πόρτες θα συνδυάζουν σε μια συμβολοσειρά διαφορετικά cookies που περνούν σε διαφορετικούς επικεφαλίδες cookie όπως σε:
``` ```
GET / HTTP/1.1 GET / HTTP/1.1
Host: example.com Host: example.com
@ -247,9 +247,9 @@ Resulting cookie: name=eval('test//, comment') => allowed
- Ελέγξτε αν το cookie έχει οποιαδήποτε πληροφορία μέσα του και προσπαθήστε να το τροποποιήσετε. - Ελέγξτε αν το cookie έχει οποιαδήποτε πληροφορία μέσα του και προσπαθήστε να το τροποποιήσετε.
- Προσπαθήστε να δημιουργήσετε αρκετούς λογαριασμούς με σχεδόν το ίδιο όνομα χρήστη και ελέγξτε αν μπορείτε να δείτε ομοιότητες. - Προσπαθήστε να δημιουργήσετε αρκετούς λογαριασμούς με σχεδόν το ίδιο όνομα χρήστη και ελέγξτε αν μπορείτε να δείτε ομοιότητες.
- Ελέγξτε την επιλογή "**remember me**" αν υπάρχει για να δείτε πώς λειτουργεί. Αν υπάρχει και μπορεί να είναι ευάλωτη, χρησιμοποιήστε πάντα το cookie του **remember me** χωρίς κανένα άλλο cookie. - Ελέγξτε την επιλογή "**remember me**" αν υπάρχει για να δείτε πώς λειτουργεί. Αν υπάρχει και μπορεί να είναι ευάλωτη, χρησιμοποιήστε πάντα το cookie του **remember me** χωρίς κανένα άλλο cookie.
- Ελέγξτε αν το προηγούμενο cookie λειτουργεί ακόμα και μετά την αλλαγή του κωδικού πρόσβασης. - Ελέγξτε αν το προηγούμενο cookie λειτουργεί ακόμα και μετά την αλλαγή του κωδικού.
#### **Προχωρημένες επιθέσεις με cookies** #### **Προχωρημένες επιθέσεις σε cookies**
Αν το cookie παραμένει το ίδιο (ή σχεδόν) όταν συνδέεστε, αυτό πιθανώς σημαίνει ότι το cookie σχετίζεται με κάποιο πεδίο του λογαριασμού σας (πιθανώς το όνομα χρήστη). Τότε μπορείτε να: Αν το cookie παραμένει το ίδιο (ή σχεδόν) όταν συνδέεστε, αυτό πιθανώς σημαίνει ότι το cookie σχετίζεται με κάποιο πεδίο του λογαριασμού σας (πιθανώς το όνομα χρήστη). Τότε μπορείτε να:
@ -271,7 +271,7 @@ padBuster http://web.com/home.jsp?UID=7B216A634951170FF851D6CC68FC9537858795A28E
Στη συνέχεια, θα ξεκινήσει την αποκρυπτογράφηση του cookie (μπορεί να διαρκέσει αρκετά λεπτά). Στη συνέχεια, θα ξεκινήσει την αποκρυπτογράφηση του cookie (μπορεί να διαρκέσει αρκετά λεπτά).
Εάν η επίθεση έχει εκτελεστεί επιτυχώς, τότε θα μπορούσατε να προσπαθήσετε να κρυπτογραφήσετε μια συμβολοσειρά της επιλογής σας. Για παράδειγμα, αν θέλατε να **κρυπτογραφήσετε** **user=administrator**. Εάν η επίθεση έχει εκτελεστεί επιτυχώς, τότε μπορείτε να προσπαθήσετε να κρυπτογραφήσετε μια συμβολοσειρά της επιλογής σας. Για παράδειγμα, αν θέλετε να **encrypt** **user=administrator**
``` ```
padbuster http://web.com/index.php 1dMjA5hfXh0jenxJQ0iW6QXKkzAGIWsiDAKV3UwJPT2lBP+zAD0D0w== 8 -cookies thecookie=1dMjA5hfXh0jenxJQ0iW6QXKkzAGIWsiDAKV3UwJPT2lBP+zAD0D0w== -plaintext user=administrator padbuster http://web.com/index.php 1dMjA5hfXh0jenxJQ0iW6QXKkzAGIWsiDAKV3UwJPT2lBP+zAD0D0w== 8 -cookies thecookie=1dMjA5hfXh0jenxJQ0iW6QXKkzAGIWsiDAKV3UwJPT2lBP+zAD0D0w== -plaintext user=administrator
``` ```
@ -290,7 +290,7 @@ padbuster http://web.com/index.php 1dMjA5hfXh0jenxJQ0iW6QXKkzAGIWsiDAKV3UwJPT2lB
**ECB** **ECB**
Εάν το cookie είναι κρυπτογραφημένο χρησιμοποιώντας ECB, θα μπορούσε να είναι ευάλωτο.\ Εάν το cookie είναι κρυπτογραφημένο χρησιμοποιώντας ECB, θα μπορούσε να είναι ευάλωτο.\
Όταν συνδεθείτε, το cookie που λαμβάνετε πρέπει να είναι πάντα το ίδιο. Όταν συνδεθείτε, το cookie που λαμβάνετε πρέπει πάντα να είναι το ίδιο.
**Πώς να ανιχνεύσετε και να επιτεθείτε:** **Πώς να ανιχνεύσετε και να επιτεθείτε:**
@ -298,7 +298,7 @@ padbuster http://web.com/index.php 1dMjA5hfXh0jenxJQ0iW6QXKkzAGIWsiDAKV3UwJPT2lB
Δημιουργήστε έναν χρήστη που ονομάζεται για παράδειγμα "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" και ελέγξτε αν υπάρχει κάποιο μοτίβο στο cookie (καθώς το ECB κρυπτογραφεί με το ίδιο κλειδί κάθε μπλοκ, τα ίδια κρυπτογραφημένα bytes θα μπορούσαν να εμφανιστούν αν το όνομα χρήστη είναι κρυπτογραφημένο). Δημιουργήστε έναν χρήστη που ονομάζεται για παράδειγμα "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" και ελέγξτε αν υπάρχει κάποιο μοτίβο στο cookie (καθώς το ECB κρυπτογραφεί με το ίδιο κλειδί κάθε μπλοκ, τα ίδια κρυπτογραφημένα bytes θα μπορούσαν να εμφανιστούν αν το όνομα χρήστη είναι κρυπτογραφημένο).
Θα πρέπει να υπάρχει ένα μοτίβο (με το μέγεθος ενός χρησιμοποιούμενου μπλοκ). Έτσι, γνωρίζοντας πώς είναι κρυπτογραφημένα μια σειρά από "a", μπορείτε να δημιουργήσετε ένα όνομα χρήστη: "a"\*(μέγεθος του μπλοκ)+"admin". Στη συνέχεια, θα μπορούσατε να διαγράψετε το κρυπτογραφημένο μοτίβο ενός μπλοκ "a" από το cookie. Και θα έχετε το cookie του ονόματος χρήστη "admin". Θα πρέπει να υπάρχει ένα μοτίβο (με το μέγεθος ενός χρησιμοποιούμενου μπλοκ). Έτσι, γνωρίζοντας πώς είναι κρυπτογραφημένα μια σειρά από "a", μπορείτε να δημιουργήσετε ένα όνομα χρήστη: "a"\*(μέγεθος του μπλοκ)+"admin". Στη συνέχεια, θα μπορούσατε να διαγράψετε το κρυπτογραφημένο μοτίβο ενός μπλοκ από "a" από το cookie. Και θα έχετε το cookie του ονόματος χρήστη "admin".
## Αναφορές ## Αναφορές

View File

@ -1,27 +1,28 @@
/** /**
* HackTricks AI Chat Widget v1.15 Markdown rendering + sanitised * HackTricks AI Chat Widget v1.16 resizable sidebar
* ------------------------------------------------------------------------ * ---------------------------------------------------
* Replaces the static placeholder with a three-dot **bouncing** loader * Markdown rendering + sanitised (same as before)
* Renders assistant replies as Markdown while purging any unsafe HTML * NEW: dragtoresize panel, width persists via localStorage
* (XSS-safe via DOMPurify)
* ------------------------------------------------------------------------
*/ */
(function () { (function () {
const LOG = "[HackTricks-AI]"; const LOG = "[HackTricksAI]";
/* ---------------- Usertunable constants ---------------- */
/* ---------------- User-tunable constants ---------------- */ const MAX_CONTEXT = 3000; // highlightedtext char limit
const MAX_CONTEXT = 3000; // highlighted-text char limit const MAX_QUESTION = 500; // question char limit
const MAX_QUESTION = 500; // question char limit const MIN_W = 250; // ← resize limits →
const MAX_W = 600;
const DEF_W = 350; // default width (if nothing saved)
const TOOLTIP_TEXT = const TOOLTIP_TEXT =
"💡 Highlight any text on the page,\nthen click to ask HackTricks AI about it"; "💡 Highlight any text on the page,\nthen click to ask HackTricks AI about it";
const API_BASE = "https://www.hacktricks.ai/api/assistants/threads"; const API_BASE = "https://www.hacktricks.ai/api/assistants/threads";
const BRAND_RED = "#b31328"; // HackTricks brand const BRAND_RED = "#b31328";
/* ------------------------------ State ------------------------------ */ /* ------------------------------ State ------------------------------ */
let threadId = null; let threadId = null;
let isRunning = false; let isRunning = false;
/* ---------- helpers ---------- */
const $ = (sel, ctx = document) => ctx.querySelector(sel); const $ = (sel, ctx = document) => ctx.querySelector(sel);
if (document.getElementById("ht-ai-btn")) { if (document.getElementById("ht-ai-btn")) {
console.warn(`${LOG} Widget already injected.`); console.warn(`${LOG} Widget already injected.`);
@ -31,44 +32,37 @@
? document.addEventListener("DOMContentLoaded", init) ? document.addEventListener("DOMContentLoaded", init)
: init()); : init());
/* ==================================================================== */ /* =================================================================== */
/* 🔗 1. 3rd-party libs → Markdown & sanitiser */ /* 🔗 1. 3rdparty libs → Markdown & sanitiser */
/* ==================================================================== */ /* =================================================================== */
function loadScript(src) { function loadScript(src) {
return new Promise((resolve, reject) => { return new Promise((res, rej) => {
const s = document.createElement("script"); const s = document.createElement("script");
s.src = src; s.src = src;
s.onload = resolve; s.onload = res;
s.onerror = () => reject(new Error(`Failed to load ${src}`)); s.onerror = () => rej(new Error(`Failed to load ${src}`));
document.head.appendChild(s); document.head.appendChild(s);
}); });
} }
async function ensureDeps() { async function ensureDeps() {
const deps = []; const deps = [];
if (typeof marked === "undefined") { if (typeof marked === "undefined")
deps.push(loadScript("https://cdn.jsdelivr.net/npm/marked/marked.min.js")); deps.push(loadScript("https://cdn.jsdelivr.net/npm/marked/marked.min.js"));
} if (typeof DOMPurify === "undefined")
if (typeof DOMPurify === "undefined") {
deps.push( deps.push(
loadScript( loadScript(
"https://cdnjs.cloudflare.com/ajax/libs/dompurify/3.2.5/purify.min.js" "https://cdnjs.cloudflare.com/ajax/libs/dompurify/3.2.5/purify.min.js"
) )
); );
}
if (deps.length) await Promise.all(deps); if (deps.length) await Promise.all(deps);
} }
const mdToSafeHTML = (md) =>
DOMPurify.sanitize(marked.parse(md, { mangle: false, headerIds: false }), {
USE_PROFILES: { html: true }
});
function mdToSafeHTML(md) { /* =================================================================== */
// 1⃣ Markdown → raw HTML
const raw = marked.parse(md, { mangle: false, headerIds: false });
// 2⃣ Purify
return DOMPurify.sanitize(raw, { USE_PROFILES: { html: true } });
}
/* ==================================================================== */
async function init() { async function init() {
/* ----- make sure marked & DOMPurify are ready before anything else */
try { try {
await ensureDeps(); await ensureDeps();
} catch (e) { } catch (e) {
@ -76,14 +70,14 @@
return; return;
} }
console.log(`${LOG} Injecting widget… v1.15`); console.log(`${LOG} Injecting widget… v1.16`);
await ensureThreadId(); await ensureThreadId();
injectStyles(); injectStyles();
const btn = createFloatingButton(); const btn = createFloatingButton();
createTooltip(btn); createTooltip(btn);
const panel = createSidebar(); const panel = createSidebar(); // ← panel with resizer
const chatLog = $("#ht-ai-chat"); const chatLog = $("#ht-ai-chat");
const sendBtn = $("#ht-ai-send"); const sendBtn = $("#ht-ai-send");
const inputBox = $("#ht-ai-question"); const inputBox = $("#ht-ai-question");
@ -100,15 +94,8 @@
function addMsg(text, cls) { function addMsg(text, cls) {
const b = document.createElement("div"); const b = document.createElement("div");
b.className = `ht-msg ${cls}`; b.className = `ht-msg ${cls}`;
b[cls === "ht-ai" ? "innerHTML" : "textContent"] =
// ✨ assistant replies rendered as Markdown + sanitised cls === "ht-ai" ? mdToSafeHTML(text) : text;
if (cls === "ht-ai") {
b.innerHTML = mdToSafeHTML(text);
} else {
// user / context bubbles stay plain-text
b.textContent = text;
}
chatLog.appendChild(b); chatLog.appendChild(b);
chatLog.scrollTop = chatLog.scrollHeight; chatLog.scrollTop = chatLog.scrollHeight;
return b; return b;
@ -116,30 +103,28 @@
const LOADER_HTML = const LOADER_HTML =
'<span class="ht-loading"><span></span><span></span><span></span></span>'; '<span class="ht-loading"><span></span><span></span><span></span></span>';
function setInputDisabled(d) { const setInputDisabled = (d) => {
inputBox.disabled = d; inputBox.disabled = d;
sendBtn.disabled = d; sendBtn.disabled = d;
} };
function clearThreadCookie() { const clearThreadCookie = () => {
document.cookie = "threadId=; Path=/; Max-Age=0"; document.cookie = "threadId=; Path=/; Max-Age=0";
threadId = null; threadId = null;
} };
function resetConversation() { const resetConversation = () => {
chatLog.innerHTML = ""; chatLog.innerHTML = "";
clearThreadCookie(); clearThreadCookie();
panel.classList.remove("open"); panel.classList.remove("open");
} };
/* ------------------- Panel open / close ------------------- */ /* ------------------- Panel open / close ------------------- */
btn.addEventListener("click", () => { btn.addEventListener("click", () => {
if (!savedSelection) { if (!savedSelection) {
alert("Please highlight some text first to then ask HackTricks AI about it."); alert("Please highlight some text first.");
return; return;
} }
if (savedSelection.length > MAX_CONTEXT) { if (savedSelection.length > MAX_CONTEXT) {
alert( alert(`Highlighted text is too long. Max ${MAX_CONTEXT} chars.`);
`Highlighted text is too long (${savedSelection.length} chars). Max allowed: ${MAX_CONTEXT}.`
);
return; return;
} }
chatLog.innerHTML = ""; chatLog.innerHTML = "";
@ -157,11 +142,10 @@
addMsg("Please wait until the current operation completes.", "ht-ai"); addMsg("Please wait until the current operation completes.", "ht-ai");
return; return;
} }
isRunning = true; isRunning = true;
setInputDisabled(true); setInputDisabled(true);
const loadingBubble = addMsg("", "ht-ai"); const loading = addMsg("", "ht-ai");
loadingBubble.innerHTML = LOADER_HTML; loading.innerHTML = LOADER_HTML;
const content = context const content = context
? `### Context:\n${context}\n\n### Question to answer:\n${question}` ? `### Context:\n${context}\n\n### Question to answer:\n${question}`
@ -178,43 +162,39 @@
try { try {
const e = await res.json(); const e = await res.json();
if (e.error) err = `Error: ${e.error}`; if (e.error) err = `Error: ${e.error}`;
else if (res.status === 429) else if (res.status === 429) err = "Rate limit exceeded.";
err = "Rate limit exceeded. Please try again later.";
} catch (_) {} } catch (_) {}
loadingBubble.textContent = err; loading.textContent = err;
return; return;
} }
const data = await res.json(); const data = await res.json();
loadingBubble.remove(); loading.remove();
if (Array.isArray(data.response)) if (Array.isArray(data.response))
data.response.forEach((p) => { data.response.forEach((p) =>
addMsg( addMsg(
p.type === "text" && p.text && p.text.value p.type === "text" && p.text && p.text.value
? p.text.value ? p.text.value
: JSON.stringify(p), : JSON.stringify(p),
"ht-ai" "ht-ai"
); )
}); );
else if (typeof data.response === "string") else if (typeof data.response === "string")
addMsg(data.response, "ht-ai"); addMsg(data.response, "ht-ai");
else addMsg(JSON.stringify(data, null, 2), "ht-ai"); else addMsg(JSON.stringify(data, null, 2), "ht-ai");
} catch (e) { } catch (e) {
console.error("Error sending message:", e); console.error("Error sending message:", e);
loadingBubble.textContent = "An unexpected error occurred."; loading.textContent = "An unexpected error occurred.";
} finally { } finally {
isRunning = false; isRunning = false;
setInputDisabled(false); setInputDisabled(false);
chatLog.scrollTop = chatLog.scrollHeight; chatLog.scrollTop = chatLog.scrollHeight;
} }
} }
async function handleSend() { async function handleSend() {
const q = inputBox.value.trim(); const q = inputBox.value.trim();
if (!q) return; if (!q) return;
if (q.length > MAX_QUESTION) { if (q.length > MAX_QUESTION) {
alert( alert(`Question too long (${q.length}). Max ${MAX_QUESTION}.`);
`Your question is too long (${q.length} chars). Max allowed: ${MAX_QUESTION}.`
);
return; return;
} }
inputBox.value = ""; inputBox.value = "";
@ -228,9 +208,9 @@
handleSend(); handleSend();
} }
}); });
} } /* end init */
/* ==================================================================== */ /* =================================================================== */
async function ensureThreadId() { async function ensureThreadId() {
const m = document.cookie.match(/threadId=([^;]+)/); const m = document.cookie.match(/threadId=([^;]+)/);
if (m && m[1]) { if (m && m[1]) {
@ -241,62 +221,67 @@
const r = await fetch(API_BASE, { method: "POST", credentials: "include" }); const r = await fetch(API_BASE, { method: "POST", credentials: "include" });
const d = await r.json(); const d = await r.json();
if (!r.ok || !d.threadId) throw new Error(`${r.status} ${r.statusText}`); if (!r.ok || !d.threadId) throw new Error(`${r.status} ${r.statusText}`);
threadId = d.threadId; threadId = d.threadId;
document.cookie = document.cookie =
`threadId=${threadId}; Path=/; Secure; SameSite=Strict; Max-Age=7200`; `threadId=${threadId}; Path=/; Secure; SameSite=Strict; Max-Age=7200`;
} catch (e) { } catch (e) {
console.error("Error creating threadId:", e); console.error("Error creating threadId:", e);
alert("Failed to initialise the conversation. Please refresh and try again."); alert("Failed to initialise the conversation. Please refresh.");
throw e; throw e;
} }
} }
/* ==================================================================== */ /* =================================================================== */
function injectStyles() { function injectStyles() {
const css = ` const css = `
#ht-ai-btn{position:fixed;bottom:20px;left:50%;transform:translateX(-50%);width:60px;height:60px;border-radius:50%;background:#1e1e1e;color:#fff;font-size:28px;display:flex;align-items:center;justify-content:center;cursor:pointer;z-index:99999;box-shadow:0 2px 8px rgba(0,0,0,.4);transition:opacity .2s} #ht-ai-btn{position:fixed;bottom:20px;left:50%;transform:translateX(-50%);min-width:60px;height:60px;border-radius:30px;background:linear-gradient(45deg, #b31328, #d42d3f, #2d5db4, #3470e4);background-size:300% 300%;animation:gradientShift 8s ease infinite;color:#fff;font-size:18px;display:flex;align-items:center;justify-content:center;cursor:pointer;z-index:99999;box-shadow:0 2px 8px rgba(0,0,0,.4);transition:opacity .2s;padding:0 20px}
#ht-ai-btn:hover{opacity:.85} #ht-ai-btn span{margin-left:8px;font-weight:bold}
@media(max-width:768px){#ht-ai-btn{display:none}} @keyframes gradientShift{0%{background-position:0% 50%}50%{background-position:100% 50%}100%{background-position:0% 50%}}
#ht-ai-tooltip{position:fixed;padding:6px 8px;background:#111;color:#fff;border-radius:4px;font-size:13px;white-space:pre-wrap;pointer-events:none;opacity:0;transform:translate(-50%,-8px);transition:opacity .15s ease,transform .15s ease;z-index:100000} #ht-ai-btn:hover{opacity:.85}
#ht-ai-tooltip.show{opacity:1;transform:translate(-50%,-12px)} @media(max-width:768px){#ht-ai-btn{display:none}}
#ht-ai-panel{position:fixed;top:0;right:0;height:100%;width:350px;max-width:90vw;background:#000;color:#fff;display:flex;flex-direction:column;transform:translateX(100%);transition:transform .3s ease;z-index:100000;font-family:system-ui,-apple-system,Segoe UI,Roboto,"Helvetica Neue",Arial,sans-serif} #ht-ai-tooltip{position:fixed;padding:6px 8px;background:#111;color:#fff;border-radius:4px;font-size:13px;white-space:pre-wrap;pointer-events:none;opacity:0;transform:translate(-50%,-8px);transition:opacity .15s ease,transform .15s ease;z-index:100000}
#ht-ai-panel.open{transform:translateX(0)} #ht-ai-tooltip.show{opacity:1;transform:translate(-50%,-12px)}
@media(max-width:768px){#ht-ai-panel{display:none}} #ht-ai-panel{position:fixed;top:0;right:0;height:100%;max-width:90vw;background:#000;color:#fff;display:flex;flex-direction:column;transform:translateX(100%);transition:transform .3s ease;z-index:100000;font-family:system-ui,-apple-system,Segoe UI,Roboto,"Helvetica Neue",Arial,sans-serif}
#ht-ai-header{display:flex;justify-content:space-between;align-items:center;padding:12px 16px;border-bottom:1px solid #333} #ht-ai-panel.open{transform:translateX(0)}
#ht-ai-header .ht-actions{display:flex;gap:8px;align-items:center} @media(max-width:768px){#ht-ai-panel{display:none}}
#ht-ai-close,#ht-ai-reset{cursor:pointer;font-size:18px;background:none;border:none;color:#fff;padding:0} #ht-ai-header{display:flex;justify-content:space-between;align-items:center;padding:12px 16px;border-bottom:1px solid #333}
#ht-ai-close:hover,#ht-ai-reset:hover{opacity:.7} #ht-ai-header .ht-actions{display:flex;gap:8px;align-items:center}
#ht-ai-chat{flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:12px;font-size:14px} #ht-ai-close,#ht-ai-reset{cursor:pointer;font-size:18px;background:none;border:none;color:#fff;padding:0}
.ht-msg{max-width:90%;line-height:1.4;padding:10px 12px;border-radius:8px;white-space:pre-wrap;word-wrap:break-word} #ht-ai-close:hover,#ht-ai-reset:hover{opacity:.7}
.ht-user{align-self:flex-end;background:${BRAND_RED}} #ht-ai-chat{flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:12px;font-size:14px}
.ht-ai{align-self:flex-start;background:#222} .ht-msg{max-width:90%;line-height:1.4;padding:10px 12px;border-radius:8px;white-space:pre-wrap;word-wrap:break-word}
.ht-context{align-self:flex-start;background:#444;font-style:italic;font-size:13px} .ht-user{align-self:flex-end;background:${BRAND_RED}}
#ht-ai-input{display:flex;gap:8px;padding:12px 16px;border-top:1px solid #333} .ht-ai{align-self:flex-start;background:#222}
#ht-ai-question{flex:1;min-height:40px;max-height:120px;resize:vertical;padding:8px;border-radius:6px;border:none;font-size:14px} .ht-context{align-self:flex-start;background:#444;font-style:italic;font-size:13px}
#ht-ai-send{padding:0 18px;border:none;border-radius:6px;background:${BRAND_RED};color:#fff;font-size:14px;cursor:pointer} #ht-ai-input{display:flex;gap:8px;padding:12px 16px;border-top:1px solid #333}
#ht-ai-send:disabled{opacity:.5;cursor:not-allowed} #ht-ai-question{flex:1;min-height:40px;max-height:120px;resize:vertical;padding:8px;border-radius:6px;border:none;font-size:14px}
/* Loader animation */ #ht-ai-send{padding:0 18px;border:none;border-radius:6px;background:${BRAND_RED};color:#fff;font-size:14px;cursor:pointer}
.ht-loading{display:inline-flex;align-items:center;gap:4px} #ht-ai-send:disabled{opacity:.5;cursor:not-allowed}
.ht-loading span{width:6px;height:6px;border-radius:50%;background:#888;animation:ht-bounce 1.2s infinite ease-in-out} /* Loader */
.ht-loading span:nth-child(2){animation-delay:0.2s} .ht-loading{display:inline-flex;align-items:center;gap:4px}
.ht-loading span:nth-child(3){animation-delay:0.4s} .ht-loading span{width:6px;height:6px;border-radius:50%;background:#888;animation:ht-bounce 1.2s infinite ease-in-out}
@keyframes ht-bounce{0%,80%,100%{transform:scale(0);}40%{transform:scale(1);} } .ht-loading span:nth-child(2){animation-delay:0.2s}
::selection{background:#ffeb3b;color:#000} .ht-loading span:nth-child(3){animation-delay:0.4s}
::-moz-selection{background:#ffeb3b;color:#000}`; @keyframes ht-bounce{0%,80%,100%{transform:scale(0);}40%{transform:scale(1);} }
::selection{background:#ffeb3b;color:#000}
::-moz-selection{background:#ffeb3b;color:#000}
/* NEW: resizer handle */
#ht-ai-resizer{position:absolute;left:0;top:0;width:6px;height:100%;cursor:ew-resize;background:transparent}
#ht-ai-resizer:hover{background:rgba(255,255,255,.05)}`;
const s = document.createElement("style"); const s = document.createElement("style");
s.id = "ht-ai-style"; s.id = "ht-ai-style";
s.textContent = css; s.textContent = css;
document.head.appendChild(s); document.head.appendChild(s);
} }
/* =================================================================== */
function createFloatingButton() { function createFloatingButton() {
const d = document.createElement("div"); const d = document.createElement("div");
d.id = "ht-ai-btn"; d.id = "ht-ai-btn";
d.textContent = "🤖"; d.innerHTML = "🤖<span>HackTricksAI</span>";
document.body.appendChild(d); document.body.appendChild(d);
return d; return d;
} }
function createTooltip(btn) { function createTooltip(btn) {
const t = document.createElement("div"); const t = document.createElement("div");
t.id = "ht-ai-tooltip"; t.id = "ht-ai-tooltip";
@ -311,11 +296,16 @@
btn.addEventListener("mouseleave", () => t.classList.remove("show")); btn.addEventListener("mouseleave", () => t.classList.remove("show"));
} }
/* =================================================================== */
function createSidebar() { function createSidebar() {
const saved = parseInt(localStorage.getItem("htAiWidth") || DEF_W, 10);
const width = Math.min(Math.max(saved, MIN_W), MAX_W);
const p = document.createElement("div"); const p = document.createElement("div");
p.id = "ht-ai-panel"; p.id = "ht-ai-panel";
p.style.width = width + "px"; // ← applied width
p.innerHTML = ` p.innerHTML = `
<div id="ht-ai-header"><strong>HackTricks AI Chat</strong> <div id="ht-ai-header"><strong>HackTricks AI Chat</strong>
<div class="ht-actions"> <div class="ht-actions">
<button id="ht-ai-reset" title="Reset"></button> <button id="ht-ai-reset" title="Reset"></button>
<span id="ht-ai-close" title="Close"></span> <span id="ht-ai-close" title="Close"></span>
@ -326,7 +316,39 @@
<textarea id="ht-ai-question" placeholder="Type your question…"></textarea> <textarea id="ht-ai-question" placeholder="Type your question…"></textarea>
<button id="ht-ai-send">Send</button> <button id="ht-ai-send">Send</button>
</div>`; </div>`;
/* NEW: resizer strip */
const resizer = document.createElement("div");
resizer.id = "ht-ai-resizer";
p.appendChild(resizer);
document.body.appendChild(p); document.body.appendChild(p);
addResizeLogic(resizer, p);
return p; return p;
} }
/* ---------------- resize behaviour ---------------- */
function addResizeLogic(handle, panel) {
let startX, startW, dragging = false;
const onMove = (e) => {
if (!dragging) return;
const dx = startX - e.clientX; // dragging leftwards ⇒ +dx
let newW = startW + dx;
newW = Math.min(Math.max(newW, MIN_W), MAX_W);
panel.style.width = newW + "px";
};
const onUp = () => {
if (!dragging) return;
dragging = false;
localStorage.setItem("htAiWidth", parseInt(panel.style.width, 10));
document.removeEventListener("mousemove", onMove);
document.removeEventListener("mouseup", onUp);
};
handle.addEventListener("mousedown", (e) => {
dragging = true;
startX = e.clientX;
startW = parseInt(window.getComputedStyle(panel).width, 10);
document.addEventListener("mousemove", onMove);
document.addEventListener("mouseup", onUp);
});
}
})(); })();