mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['src/pentesting-web/hacking-with-cookies/README.md'] to af
This commit is contained in:
parent
69c46a0a55
commit
29c630d38b
@ -8,15 +8,15 @@ Koekies kom met verskeie attribuut wat hul gedrag in die gebruiker se blaaiers b
|
|||||||
|
|
||||||
### Vervaldatum en Max-Age
|
### Vervaldatum en Max-Age
|
||||||
|
|
||||||
Die vervaldatum van 'n koekie word bepaal deur die `Expires` attribuut. Omgekeerd definieer die `Max-age` attribuut die tyd in sekondes totdat 'n koekie verwyder word. **Kies vir `Max-age` aangesien dit meer moderne praktyke weerspieël.**
|
Die vervaldatum van 'n koekie word bepaal deur die `Expires` attribuut. Omgekeerd, die `Max-age` attribuut definieer die tyd in sekondes totdat 'n koekie verwyder word. **Kies vir `Max-age` aangesien dit meer moderne praktyke weerspieël.**
|
||||||
|
|
||||||
### Domein
|
### Domein
|
||||||
|
|
||||||
Die gasheer wat 'n koekie ontvang, word gespesifiseer deur die `Domain` attribuut. Standaard is dit ingestel op die gasheer wat die koekie uitgereik het, sonder om sy subdomeine in te sluit. Wanneer die `Domain` attribuut egter eksplisiet ingestel word, sluit dit ook subdomeine in. Dit maak die spesifikasie van die `Domain` attribuut 'n minder beperkende opsie, nuttig vir scenario's waar koekie deel tussen subdomeine nodig is. Byvoorbeeld, om `Domain=mozilla.org` in te stel, maak koekies beskikbaar op sy subdomeine soos `developer.mozilla.org`.
|
Die gasheer wat 'n koekie ontvang, word gespesifiseer deur die `Domain` attribuut. Standaard is dit ingestel op die gasheer wat die koekie uitgereik het, sonder om sy subdomeine in te sluit. Wanneer die `Domain` attribuut egter eksplisiet ingestel word, sluit dit ook subdomeine in. Dit maak die spesifikasie van die `Domain` attribuut 'n minder beperkende opsie, nuttig vir scenario's waar koekie deel oor subdomeine nodig is. Byvoorbeeld, om `Domain=mozilla.org` in te stel, maak koekies beskikbaar op sy subdomeine soos `developer.mozilla.org`.
|
||||||
|
|
||||||
### Pad
|
### Pad
|
||||||
|
|
||||||
'n Spesifieke URL-pad wat teenwoordig moet wees in die versoekte URL vir die `Cookie` kop om gestuur te word, word aangedui deur die `Path` attribuut. Hierdie attribuut beskou die `/` karakter as 'n gids skeider, wat ooreenkomste in subgidse moontlik maak.
|
'n Spesifieke URL-pad wat teenwoordig moet wees in die versoekte URL vir die `Cookie` kop om gestuur te word, word aangedui deur die `Path` attribuut. Hierdie attribuut beskou die `/` karakter as 'n gids skeidingsteken, wat ooreenkomste in subgidse moontlik maak.
|
||||||
|
|
||||||
### Bestellingsreëls
|
### Bestellingsreëls
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ Wanneer twee koekies dieselfde naam het, word die een wat gekies word om te stuu
|
|||||||
- Die `SameSite` attribuut bepaal of koekies gestuur word op versoeke wat afkomstig is van derdeparty-domeine. Dit bied drie instellings:
|
- Die `SameSite` attribuut bepaal of koekies gestuur word op versoeke wat afkomstig is van derdeparty-domeine. Dit bied drie instellings:
|
||||||
- **Streng**: Beperk die koekie om nie op derdeparty versoeke gestuur te word nie.
|
- **Streng**: Beperk die koekie om nie op derdeparty versoeke gestuur te word nie.
|
||||||
- **Lax**: Laat die koekie toe om gestuur te word met GET versoeke wat deur derdeparty-webwerwe geïnisieer word.
|
- **Lax**: Laat die koekie toe om gestuur te word met GET versoeke wat deur derdeparty-webwerwe geïnisieer word.
|
||||||
- **Geen**: Laat die koekie toe om van enige derdeparty-domein gestuur te word.
|
- **Geen**: Laat die koekie toe om gestuur te word vanaf enige derdeparty-domein.
|
||||||
|
|
||||||
Onthou, terwyl jy koekies konfigureer, kan die begrip van hierdie attribuut help om te verseker dat hulle soos verwag oor verskillende scenario's optree.
|
Onthou, terwyl jy koekies konfigureer, kan die begrip van hierdie attribuut help om te verseker dat hulle soos verwag oor verskillende scenario's optree.
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ Tabel van [Invicti](https://www.netsparker.com/blog/web-security/same-site-cooki
|
|||||||
'n Koekie met _**SameSite**_ attribuut sal **CSRF-aanvalle verminder** waar 'n ingelogde sessie nodig is.
|
'n Koekie met _**SameSite**_ attribuut sal **CSRF-aanvalle verminder** waar 'n ingelogde sessie nodig is.
|
||||||
|
|
||||||
**\*Let daarop dat vanaf Chrome80 (feb/2019) die standaard gedrag van 'n koekie sonder 'n koekie samesite** **attribuut sal lax wees** ([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/)).\
|
**\*Let daarop dat vanaf Chrome80 (feb/2019) die standaard gedrag van 'n koekie sonder 'n koekie samesite** **attribuut sal lax wees** ([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/)).\
|
||||||
Let daarop dat tydelik, na die toepassing van hierdie verandering, die **koekies sonder 'n SameSite** **beleid** in Chrome sal **as Geen behandel word** gedurende die **eerste 2 minute en dan as Lax vir topvlak kruis-web POST versoek.**
|
Let daarop dat tydelik, na die toepassing van hierdie verandering, die **koekies sonder 'n SameSite** **beleid** in Chrome sal **behandel word as Geen** gedurende die **eerste 2 minute en dan as Lax vir topvlak kruis-web POST versoek.**
|
||||||
|
|
||||||
## Koekies Vlaggies
|
## Koekies Vlaggies
|
||||||
|
|
||||||
@ -58,9 +58,9 @@ Dit verhoed dat die **klient** toegang tot die koekie het (Via **Javascript** by
|
|||||||
|
|
||||||
#### **Omseilings**
|
#### **Omseilings**
|
||||||
|
|
||||||
- As die bladsy **die koekies as die antwoord** van 'n versoek stuur (byvoorbeeld in 'n **PHPinfo** bladsy), is dit moontlik om die XSS te misbruik om 'n versoek na hierdie bladsy te stuur en **die koekies** uit die antwoord te **steel** (kyk 'n voorbeeld in [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/)).
|
- As die bladsy **die koekies as die antwoord** van 'n versoek stuur (byvoorbeeld in 'n **PHPinfo** bladsy), is dit moontlik om die XSS te misbruik om 'n versoek na hierdie bladsy te stuur en **die koekies** uit die antwoord te **steel** (kyk 'n voorbeeld in [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/)).
|
||||||
- Dit kan omseil word met **TRACE** **HTTP** versoeke aangesien die antwoord van die bediener (as hierdie HTTP metode beskikbaar is) die koekies wat gestuur is, sal weerspieël. Hierdie tegniek word **Cross-Site Tracking** genoem.
|
- Dit kan omseil word met **TRACE** **HTTP** versoeke aangesien die antwoord van die bediener (as hierdie HTTP metode beskikbaar is) die koekies wat gestuur is, sal weerspieël. Hierdie tegniek word **Cross-Site Tracking** genoem.
|
||||||
- Hierdie tegniek word vermy deur **moderne blaaiers deur nie toe te laat om 'n TRACE** versoek van JS te stuur nie. Daar is egter sekere omseilings in spesifieke sagteware gevind, soos om `\r\nTRACE` in plaas van `TRACE` na IE6.0 SP2 te stuur.
|
- Hierdie tegniek word vermy deur **moderne blaaiers deur nie toe te laat om 'n TRACE** versoek van JS te stuur. Daar is egter sekere omseilings in spesifieke sagteware gevind, soos om `\r\nTRACE` in plaas van `TRACE` na IE6.0 SP2 te stuur.
|
||||||
- 'n Ander manier is die uitbuiting van nul/dag kwesbaarhede van die blaaiers.
|
- 'n Ander manier is die uitbuiting van nul/dag kwesbaarhede van die blaaiers.
|
||||||
- Dit is moontlik om **HttpOnly koekies** te oorskry deur 'n Koekie Jar oorgeloop aanval uit te voer:
|
- Dit is moontlik om **HttpOnly koekies** te oorskry deur 'n Koekie Jar oorgeloop aanval uit te voer:
|
||||||
|
|
||||||
@ -68,7 +68,7 @@ Dit verhoed dat die **klient** toegang tot die koekie het (Via **Javascript** by
|
|||||||
cookie-jar-overflow.md
|
cookie-jar-overflow.md
|
||||||
{{#endref}}
|
{{#endref}}
|
||||||
|
|
||||||
- Dit is moontlik om [**Koekie Smuggling**](#cookie-smuggling) aanval te gebruik om hierdie koekies te ekfiltreer.
|
- Dit is moontlik om [**Cookie Smuggling**](#cookie-smuggling) aanval te gebruik om hierdie koekies te ekfiltreer.
|
||||||
|
|
||||||
### Veilige
|
### Veilige
|
||||||
|
|
||||||
@ -76,20 +76,20 @@ Die versoek sal **slegs** die koekie in 'n HTTP versoek stuur as die versoek oor
|
|||||||
|
|
||||||
## Koekies Vooraf
|
## Koekies Vooraf
|
||||||
|
|
||||||
Koekies wat met `__Secure-` voorafgegaan word, moet saam met die `secure` vlag van bladsye wat deur HTTPS beveilig is, ingestel word.
|
Koekies wat met `__Secure-` begin, moet saam met die `secure` vlag van bladsye wat deur HTTPS beveilig is, ingestel word.
|
||||||
|
|
||||||
Vir koekies wat met `__Host-` voorafgegaan word, moet verskeie voorwaardes nagekom word:
|
Vir koekies wat met `__Host-` begin, moet verskeie voorwaardes nagekom word:
|
||||||
|
|
||||||
- Hulle moet met die `secure` vlag ingestel word.
|
- Hulle moet met die `secure` vlag ingestel word.
|
||||||
- Hulle moet afkomstig wees van 'n bladsy wat deur HTTPS beveilig is.
|
- Hulle moet afkomstig wees van 'n bladsy wat deur HTTPS beveilig is.
|
||||||
- Hulle is verbode om 'n domein te spesifiseer, wat hul oordrag na subdomeine voorkom.
|
- Hulle is verbode om 'n domein te spesifiseer, wat hul oordrag na subdomeine voorkom.
|
||||||
- Die pad vir hierdie koekies moet op `/` ingestel wees.
|
- Die pad vir hierdie koekies moet op `/` ingestel wees.
|
||||||
|
|
||||||
Dit is belangrik om te noem dat koekies wat met `__Host-` voorafgegaan word, nie toegelaat word om na superdomeine of subdomeine gestuur te word nie. Hierdie beperking help om toepassingskoekies te isoleer. Dus, om die `__Host-` voorvoegsel vir alle toepassingskoekies te gebruik, kan beskou word as 'n goeie praktyk om sekuriteit en isolasie te verbeter.
|
Dit is belangrik om daarop te let dat koekies wat met `__Host-` begin, nie toegelaat word om na superdomeine of subdomeine gestuur te word nie. Hierdie beperking help om toepassingskoekies te isoleer. Dus, om die `__Host-` voorvoegsel vir alle toepassingskoekies te gebruik, kan beskou word as 'n goeie praktyk om sekuriteit en isolasie te verbeter.
|
||||||
|
|
||||||
### Oorskry van koekies
|
### Oorskry van koekies
|
||||||
|
|
||||||
So, een van die beskermings van `__Host-` voorafgegaan koekies is om te voorkom dat hulle van subdomeine oorgeskryf word. Dit voorkom byvoorbeeld [**Koekie Tossing aanvalle**](cookie-tossing.md). In die praatjie [**Koekies Krummel: Ontsluiting van Web Sessies Integriteit Kwesbaarhede**](https://www.youtube.com/watch?v=F_wAzF4a7Xg) ([**papier**](https://www.usenix.org/system/files/usenixsecurity23-squarcina.pdf)) word aangebied dat dit moontlik was om \_\_HOST- voorafgegaan koekies van subdomein in te stel, deur die parser te bedrieg, byvoorbeeld, om "=" aan die begin of aan die begin en die einde by te voeg...:
|
So, een van die beskermings van `__Host-` voorvoegsel koekies is om te voorkom dat hulle van subdomeine oorgeskryf word. Dit voorkom byvoorbeeld [**Cookie Tossing aanvalle**](cookie-tossing.md). In die praatjie [**Cookie Crumbles: Unveiling Web Session Integrity Vulnerabilities**](https://www.youtube.com/watch?v=F_wAzF4a7Xg) ([**papier**](https://www.usenix.org/system/files/usenixsecurity23-squarcina.pdf)) word aangebied dat dit moontlik was om \_\_HOST- voorvoegsel koekies van subdomein in te stel, deur die parser te bedrieg, byvoorbeeld, om "=" aan die begin of aan die begin en die einde by te voeg...:
|
||||||
|
|
||||||
<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>
|
||||||
|
|
||||||
@ -99,19 +99,19 @@ Of in PHP was dit moontlik om **ander karakters aan die begin** van die koekie n
|
|||||||
|
|
||||||
## Koekies Aanvalle
|
## Koekies Aanvalle
|
||||||
|
|
||||||
As 'n pasgemaakte koekie sensitiewe data bevat, kyk daarna (veral as jy 'n CTF speel), aangesien dit kwesbaar mag wees.
|
As 'n pasgemaakte koekie sensitiewe data bevat, kyk dit (veral as jy 'n CTF speel), aangesien dit kwesbaar mag wees.
|
||||||
|
|
||||||
### Dekodering en Manipulering van Koekies
|
### Dekodering en Manipulasie van Koekies
|
||||||
|
|
||||||
Sensitiewe data wat in koekies ingebed is, moet altyd ondersoek word. Koekies wat in Base64 of soortgelyke formate gekodeer is, kan dikwels gedekodeer word. Hierdie kwesbaarheid laat aanvallers toe om die koekie se inhoud te verander en ander gebruikers na te boots deur hul gewysigde data terug in die koekie te kodeer.
|
Sensitiewe data wat in koekies ingebed is, moet altyd ondersoek word. Koekies wat in Base64 of soortgelyke formate gekodeer is, kan dikwels gedekodeer word. Hierdie kwesbaarheid laat aanvallers toe om die koekie se inhoud te verander en ander gebruikers na te boots deur hul gewysigde data weer in die koekie te kodeer.
|
||||||
|
|
||||||
### Sessiediefstal
|
### Sessiediefstal
|
||||||
|
|
||||||
Hierdie aanval behels die steel van 'n gebruiker se koekie om ongeoorloofde toegang tot hul rekening binne 'n toepassing te verkry. Deur die gesteelde koekie te gebruik, kan 'n aanvaller die wettige gebruiker na boots.
|
Hierdie aanval behels die steel van 'n gebruiker se koekie om ongeoorloofde toegang tot hul rekening binne 'n toepassing te verkry. Deur die gesteelde koekie te gebruik, kan 'n aanvaller die wettige gebruiker naboots.
|
||||||
|
|
||||||
### Sessiefiksasie
|
### Sessiefiksasie
|
||||||
|
|
||||||
In hierdie scenario bedrieg 'n aanvaller 'n slagoffer om 'n spesifieke koekie te gebruik om in te log. As die toepassing nie 'n nuwe koekie toeken nie wanneer daar ingelog word, kan die aanvaller, wat die oorspronklike koekie besit, die slagoffer na boots. Hierdie tegniek is afhanklik van die slagoffer wat inlog met 'n koekie wat deur die aanvaller verskaf is.
|
In hierdie scenario bedrieg 'n aanvaller 'n slagoffer om 'n spesifieke koekie te gebruik om in te log. As die toepassing nie 'n nuwe koekie toeken nie wanneer daar ingelog word, kan die aanvaller, wat die oorspronklike koekie besit, die slagoffer naboots. Hierdie tegniek staat op die slagoffer wat inlog met 'n koekie wat deur die aanvaller verskaf is.
|
||||||
|
|
||||||
As jy 'n **XSS in 'n subdomein** gevind het of jy **beheer 'n subdomein**, lees:
|
As jy 'n **XSS in 'n subdomein** gevind het of jy **beheer 'n subdomein**, lees:
|
||||||
|
|
||||||
@ -155,7 +155,7 @@ document.cookie = `${name}=${value}`
|
|||||||
|
|
||||||
setCookie("", "a=b") // Setting the empty cookie modifies another cookie's value
|
setCookie("", "a=b") // Setting the empty cookie modifies another cookie's value
|
||||||
```
|
```
|
||||||
Dit lei daartoe dat die blaaiert 'n koekie-kop stuur wat deur elke webbediener geïnterpreteer word as 'n koekie met die naam `a` en 'n waarde `b`.
|
Dit lei daartoe dat die blaaiert 'n koekie-header stuur wat deur elke webbediener geïnterpreteer word as 'n koekie met die naam `a` en 'n waarde `b`.
|
||||||
|
|
||||||
#### Chrome Fout: Unicode Surrogate Codepoint Probleem
|
#### Chrome Fout: Unicode Surrogate Codepoint Probleem
|
||||||
|
|
||||||
@ -165,15 +165,15 @@ document.cookie = "\ud800=meep"
|
|||||||
```
|
```
|
||||||
Dit lei tot `document.cookie` wat 'n leë string uitset, wat permanente korrupsie aandui.
|
Dit lei tot `document.cookie` wat 'n leë string uitset, wat permanente korrupsie aandui.
|
||||||
|
|
||||||
#### Koekie Smuggling Weens Parsing Probleme
|
#### Koekie Smuggling As gevolg van Parsing Probleme
|
||||||
|
|
||||||
(Kyk na verdere besonderhede in die [oorspronklike navorsing](https://blog.ankursundara.com/cookie-bugs/)) Verskeie webbedieners, insluitend dié van Java (Jetty, TomCat, Undertow) en Python (Zope, cherrypy, web.py, aiohttp, bottle, webob), hanteer koekie stringe verkeerd weens verouderde RFC2965 ondersteuning. Hulle lees 'n dubbel-aanhaling koekiewaarde as 'n enkele waarde, selfs al sluit dit puntkommas in, wat normaalweg sleutel-waarde pare moet skei:
|
(Kyk na verdere besonderhede in die [oorspronklike navorsing](https://blog.ankursundara.com/cookie-bugs/)) Verskeie webbedieners, insluitend dié van Java (Jetty, TomCat, Undertow) en Python (Zope, cherrypy, web.py, aiohttp, bottle, webob), hanteer koekie stringe verkeerd as gevolg van verouderde RFC2965 ondersteuning. Hulle lees 'n dubbel-aanhaling koekiewaarde as 'n enkele waarde, selfs al sluit dit puntkomma's in, wat normaalweg sleutel-waarde pare moet skei:
|
||||||
```
|
```
|
||||||
RENDER_TEXT="hello world; JSESSIONID=13371337; ASDF=end";
|
RENDER_TEXT="hello world; JSESSIONID=13371337; ASDF=end";
|
||||||
```
|
```
|
||||||
#### Koekie-inspuitingskw vulnerabilities
|
#### Koekie-inspuitingskw vulnerabilities
|
||||||
|
|
||||||
(Kyk na verdere besonderhede in die [oorspronklike navorsing](https://blog.ankursundara.com/cookie-bugs/)) Die onakkurate ontleding van koekies deur bedieners, veral Undertow, Zope, en dié wat Python se `http.cookie.SimpleCookie` en `http.cookie.BaseCookie` gebruik, skep geleenthede vir koekie-inspuitingsaanvalle. Hierdie bedieners slaag nie daarin om die begin van nuwe koekies behoorlik te begrens nie, wat dit moontlik maak vir aanvallers om koekies na te maak:
|
(Kyk na verdere besonderhede in die [oorspronklike navorsing](https://blog.ankursundara.com/cookie-bugs/)) Die onkorrekte ontleding van koekies deur bedieners, veral Undertow, Zope, en dié wat Python se `http.cookie.SimpleCookie` en `http.cookie.BaseCookie` gebruik, skep geleenthede vir koekie-inspuitingsaanvalle. Hierdie bedieners slaag nie daarin om die begin van nuwe koekies behoorlik te begrens nie, wat dit vir aanvallers moontlik maak om koekies na te maak:
|
||||||
|
|
||||||
- Undertow verwag 'n nuwe koekie onmiddellik na 'n aangehaalde waarde sonder 'n puntkomma.
|
- Undertow verwag 'n nuwe koekie onmiddellik na 'n aangehaalde waarde sonder 'n puntkomma.
|
||||||
- Zope soek 'n komma om die volgende koekie te begin ontleed.
|
- Zope soek 'n komma om die volgende koekie te begin ontleed.
|
||||||
@ -183,7 +183,7 @@ Hierdie kwesbaarheid is veral gevaarlik in webtoepassings wat op koekie-gebaseer
|
|||||||
|
|
||||||
### Koekies $version
|
### Koekies $version
|
||||||
|
|
||||||
#### WAF Oorskryding
|
#### WAF Omspring
|
||||||
|
|
||||||
Volgens [**hierdie blogpos**](https://portswigger.net/research/bypassing-wafs-with-the-phantom-version-cookie), mag dit moontlik wees om die koekie-attribuut **`$Version=1`** te gebruik om die agtergrond 'n ou logika te laat gebruik om die koekie te ontleed as gevolg van die **RFC2109**. Boonop kan ander waardes soos **`$Domain`** en **`$Path`** gebruik word om die gedrag van die agtergrond met die koekie te verander.
|
Volgens [**hierdie blogpos**](https://portswigger.net/research/bypassing-wafs-with-the-phantom-version-cookie), mag dit moontlik wees om die koekie-attribuut **`$Version=1`** te gebruik om die agtergrond 'n ou logika te laat gebruik om die koekie te ontleed as gevolg van die **RFC2109**. Boonop kan ander waardes soos **`$Domain`** en **`$Path`** gebruik word om die gedrag van die agtergrond met die koekie te verander.
|
||||||
|
|
||||||
@ -194,11 +194,10 @@ Volgens [**hierdie blogpos**](https://portswigger.net/research/stealing-httponly
|
|||||||
- Vind 'n plek waar 'n blykbaar nuttelose **koekie in die antwoord weerspieël word**
|
- Vind 'n plek waar 'n blykbaar nuttelose **koekie in die antwoord weerspieël word**
|
||||||
- **Skep 'n koekie genaamd `$Version`** met die waarde `1` (jy kan dit in 'n XSS-aanval vanaf JS doen) met 'n meer spesifieke pad sodat dit die aanvanklike posisie kry (sommige raamwerke soos Python het nie hierdie stap nodig nie)
|
- **Skep 'n koekie genaamd `$Version`** met die waarde `1` (jy kan dit in 'n XSS-aanval vanaf JS doen) met 'n meer spesifieke pad sodat dit die aanvanklike posisie kry (sommige raamwerke soos Python het nie hierdie stap nodig nie)
|
||||||
- **Skep die koekie wat weerspieël word** met 'n waarde wat 'n **oop dubbele aanhalingstekens** laat en met 'n spesifieke pad sodat dit in die koekiedatabasis na die vorige een (`$Version`) geposisioneer word
|
- **Skep die koekie wat weerspieël word** met 'n waarde wat 'n **oop dubbele aanhalingstekens** laat en met 'n spesifieke pad sodat dit in die koekiedatabasis na die vorige een (`$Version`) geposisioneer word
|
||||||
- Dan sal die wettige koekie volgende in die volgorde gaan
|
- Dan sal die wettige koekie volgende in die volgorde kom
|
||||||
- **Skep 'n dummy koekie wat die dubbele aanhalingstekens** binne sy waarde sluit
|
- **Skep 'n vals koekie wat die dubbele aanhalingstekens** binne sy waarde sluit
|
||||||
|
|
||||||
Op hierdie manier word die slagoffer koekie vasgevang binne die nuwe koekie weergawe 1 en sal dit weerspieël word wanneer dit weerspieël word.
|
Op hierdie manier word die slagoffer koekie vasgevang binne die nuwe koekie weergawe 1 en sal dit weerspieël word wanneer dit weerspieël word.
|
||||||
bv. uit die pos:
|
|
||||||
```javascript
|
```javascript
|
||||||
document.cookie = `$Version=1;`;
|
document.cookie = `$Version=1;`;
|
||||||
document.cookie = `param1="start`;
|
document.cookie = `param1="start`;
|
||||||
@ -209,22 +208,22 @@ document.cookie = `param2=end";`;
|
|||||||
|
|
||||||
#### Cookies $version
|
#### Cookies $version
|
||||||
|
|
||||||
Kyk die vorige afdeling.
|
Kyk na die vorige afdeling.
|
||||||
|
|
||||||
#### Omseiling van waarde-analisering met aangehaalde-string kodering
|
#### Omseiling van waarde-analise met aangehaalde-string kodering
|
||||||
|
|
||||||
Hierdie ontleding dui aan om ontsnapte waardes binne die koekies te ontsnap, sodat "\a" "a" word. Dit kan nuttig wees om WAFS te omseil soos:
|
Hierdie ontleding dui aan om ontsnapte waardes binne die koekies te ontvlug, sodat "\a" "a" word. Dit kan nuttig wees om WAFS te omseil soos:
|
||||||
|
|
||||||
- `eval('test') => verbode`
|
- `eval('test') => verbode`
|
||||||
- `"\e\v\a\l\(\'\t\e\s\t\'\)" => toegelaat`
|
- `"\e\v\a\l\(\'\t\e\s\t\'\)" => toegelaat`
|
||||||
|
|
||||||
#### Omseiling van koekie-naam bloklyste
|
#### Omseiling van koekie-naam bloklys
|
||||||
|
|
||||||
In die RFC2109 word aangedui dat 'n **komma as 'n skeidingsteken tussen koekiewaardes gebruik kan word**. En dit is ook moontlik om **spasies en tabulasies voor en na die gelykteken by te voeg**. Daarom genereer 'n koekie soos `$Version=1; foo=bar, abc = qux` nie die koekie `"foo":"bar, admin = qux"` nie, maar die koekies `foo":"bar"` en `"admin":"qux"`. Let op hoe 2 koekies gegenereer word en hoe admin die spasie voor en na die gelykteken verwyder is.
|
In die RFC2109 word aangedui dat 'n **komma as 'n skeidingsteken tussen koekiewaardes gebruik kan word**. En dit is ook moontlik om **spasies en tabulasies voor en na die gelykteken by te voeg**. Daarom genereer 'n koekie soos `$Version=1; foo=bar, abc = qux` nie die koekie `"foo":"bar, admin = qux"` nie, maar die koekies `foo":"bar"` en `"admin":"qux"`. Let op hoe 2 koekies gegenereer word en hoe admin die spasie voor en na die gelykteken verwyder is.
|
||||||
|
|
||||||
#### Omseiling van waarde-analisering met koekie-skeiding
|
#### Omseiling van waarde-analise met koekie-skeiding
|
||||||
|
|
||||||
Laastens sou verskillende agterdeure in 'n string verskillende koekies saamvoeg wat in verskillende koekie-koptekste deurgegee word soos in:
|
Laastens sou verskillende agterdeure in 'n string verskillende koekies saamvoeg wat in verskillende koekie-kopstukke deurgegee word soos in:
|
||||||
```
|
```
|
||||||
GET / HTTP/1.1
|
GET / HTTP/1.1
|
||||||
Host: example.com
|
Host: example.com
|
||||||
@ -242,10 +241,10 @@ Resulting cookie: name=eval('test//, comment') => allowed
|
|||||||
|
|
||||||
#### **Basiese kontroles**
|
#### **Basiese kontroles**
|
||||||
|
|
||||||
- Die **koekie** is die **selfde** elke keer wanneer jy **aanmeld**.
|
- Die **koekie** is elke keer wanneer jy **aanmeld** die **dieselfde**.
|
||||||
- Meld af en probeer om dieselfde koekie te gebruik.
|
- Meld uit en probeer om dieselfde koekie te gebruik.
|
||||||
- Probeer om met 2 toestelle (of blaaiers) na dieselfde rekening aan te meld met die selfde koekie.
|
- Probeer om met 2 toestelle (of blaaiers) na dieselfde rekening aan te meld met dieselfde koekie.
|
||||||
- Kontroleer of die koekie enige inligting daarin het en probeer om dit te wysig.
|
- Kontroleer of die koekie enige inligting bevat en probeer om dit te wysig.
|
||||||
- Probeer om verskeie rekeninge met amper dieselfde gebruikersnaam te skep en kyk of jy ooreenkomste kan sien.
|
- Probeer om verskeie rekeninge met amper dieselfde gebruikersnaam te skep en kyk of jy ooreenkomste kan sien.
|
||||||
- Kontroleer die "**onthou my**" opsie indien dit bestaan om te sien hoe dit werk. As dit bestaan en kwesbaar kan wees, gebruik altyd die koekie van **onthou my** sonder enige ander koekie.
|
- Kontroleer die "**onthou my**" opsie indien dit bestaan om te sien hoe dit werk. As dit bestaan en kwesbaar kan wees, gebruik altyd die koekie van **onthou my** sonder enige ander koekie.
|
||||||
- Kontroleer of die vorige koekie werk selfs nadat jy die wagwoord verander.
|
- Kontroleer of die vorige koekie werk selfs nadat jy die wagwoord verander.
|
||||||
@ -286,14 +285,14 @@ Miskien kan 'n koekie 'n waarde hê en kan dit onderteken word met CBC. Dan is d
|
|||||||
|
|
||||||
1. Kry die handtekening van gebruikersnaam **administ** = **t**
|
1. Kry die handtekening van gebruikersnaam **administ** = **t**
|
||||||
2. Kry die handtekening van gebruikersnaam **rator\x00\x00\x00 XOR t** = **t'**
|
2. Kry die handtekening van gebruikersnaam **rator\x00\x00\x00 XOR t** = **t'**
|
||||||
3. Stel in die koekie die waarde **administrator+t'** (**t'** sal 'n geldige handtekening wees van **(rator\x00\x00\x00 XOR t) XOR t** = **rator\x00\x00\x00**
|
3. Stel in die koekie die waarde **administrator+t'** in (**t'** sal 'n geldige handtekening wees van **(rator\x00\x00\x00 XOR t) XOR t** = **rator\x00\x00\x00**
|
||||||
|
|
||||||
**ECB**
|
**ECB**
|
||||||
|
|
||||||
As die koekie met ECB versleuteld is, kan dit kwesbaar wees.\
|
As die koekie met ECB versleuteld is, kan dit kwesbaar wees.\
|
||||||
Wanneer jy aanmeld, moet die koekie wat jy ontvang altyd dieselfde wees.
|
Wanneer jy aanmeld, moet die koekie wat jy ontvang altyd dieselfde wees.
|
||||||
|
|
||||||
**Hoe om te detecteer en aan te val:**
|
**Hoe om te ontdek en aan te val:**
|
||||||
|
|
||||||
Skep 2 gebruikers met byna dieselfde data (gebruikersnaam, wagwoord, e-pos, ens.) en probeer om 'n patroon binne die gegewe koekie te ontdek.
|
Skep 2 gebruikers met byna dieselfde data (gebruikersnaam, wagwoord, e-pos, ens.) en probeer om 'n patroon binne die gegewe koekie te ontdek.
|
||||||
|
|
||||||
|
236
theme/ai.js
236
theme/ai.js
@ -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: drag‑to‑resize panel, width persists via localStorage
|
||||||
* (XSS-safe via DOMPurify)
|
|
||||||
* ------------------------------------------------------------------------
|
|
||||||
*/
|
*/
|
||||||
(function () {
|
(function () {
|
||||||
const LOG = "[HackTricks-AI]";
|
const LOG = "[HackTricks‑AI]";
|
||||||
|
/* ---------------- User‑tunable constants ---------------- */
|
||||||
/* ---------------- User-tunable constants ---------------- */
|
const MAX_CONTEXT = 3000; // highlighted‑text 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. 3rd‑party 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);
|
||||||
|
});
|
||||||
|
}
|
||||||
})();
|
})();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user