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

This commit is contained in:
Translator 2025-05-18 03:05:06 +00:00
parent 4fa140e7bf
commit da7ee1c925
2 changed files with 191 additions and 169 deletions

View File

@ -2,21 +2,21 @@
{{#include ../../banners/hacktricks-training.md}} {{#include ../../banners/hacktricks-training.md}}
## Çerez Nitelikleri ## Çerez Özellikleri
Çerezler, kullanıcının tarayıcısındaki davranışlarını kontrol eden birkaç nitelik ile gelir. İşte bu niteliklerin daha pasif bir sesle özeti: Çerezler, kullanıcının tarayıcısındaki davranışlarını kontrol eden birkaç özellik ile gelir. İşte bu özelliklerin daha pasif bir sesle bir özeti:
### Süre Dolma ve Max-Age ### Süre Dolma ve Max-Age
Bir çerezin son kullanma tarihi `Expires` niteliği ile belirlenir. Tersine, `Max-age` niteliği bir çerezin silinmesine kadar geçen süreyi saniye cinsinden tanımlar. **Daha modern uygulamaları yansıttığı için `Max-age` seçin.** Bir çerezin son kullanma tarihi `Expires` özelliği ile belirlenir. Tersine, `Max-age` özelliği, bir çerezin silinmesine kadar geçen süreyi saniye cinsinden tanımlar. **Daha modern uygulamaları yansıttığı için `Max-age` seçin.**
### Alan ### Alan
Bir çerezi alacak olan ana bilgisayarlar `Domain` niteliği ile belirtilir. Varsayılan olarak, bu çerezi veren ana bilgisayara ayarlanır, alt alan adlarını içermez. Ancak, `Domain` niteliği açıkça ayarlandığında, alt alan adlarını da kapsar. Bu, `Domain` niteliğinin belirlenmesini daha az kısıtlayıcı bir seçenek haline getirir ve alt alan adları arasında çerez paylaşımının gerekli olduğu senaryolar için faydalıdır. Örneğin, `Domain=mozilla.org` ayarlandığında, `developer.mozilla.org` gibi alt alan adlarında çerezlere erişim sağlanır. Bir çerezi alacak olan ana bilgisayarlar `Domain` özelliği ile belirtilir. Varsayılan olarak, bu çerezi veren ana bilgisayara ayarlanır, alt alan adlarını içermez. Ancak, `Domain` özelliği açıkça ayarlandığında, alt alan adlarını da kapsar. Bu, `Domain` özelliğinin belirlenmesini daha az kısıtlayıcı bir seçenek haline getirir ve alt alan adları arasında çerez paylaşımının gerekli olduğu senaryolar için faydalıdır. Örneğin, `Domain=mozilla.org` ayarlandığında, `developer.mozilla.org` gibi alt alan adlarında çerezlere erişim sağlanır.
### Yol ### Yol
`Cookie` başlığının gönderilmesi için istenen URL'de bulunması gereken belirli bir URL yolu `Path` niteliği ile belirtilir. Bu nitelik `/` karakterini bir dizin ayırıcı olarak kabul eder ve alt dizinlerde eşleşmelere de izin verir. `Cookie` başlığının gönderilmesi için istenen URL'de bulunması gereken belirli bir URL yolu `Path` özelliği ile belirtilir. Bu özellik, `/` karakterini bir dizin ayırıcı olarak kabul eder ve alt dizinlerde eşleşmelere de izin verir.
### Sıralama Kuralları ### Sıralama Kuralları
@ -27,28 +27,28 @@ Bir çerezi alacak olan ana bilgisayarlar `Domain` niteliği ile belirtilir. Var
### SameSite ### SameSite
- `SameSite` niteliği, çerezlerin üçüncü taraf alanlardan gelen isteklerde gönderilip gönderilmeyeceğini belirler. Üç ayar sunar: - `SameSite` özelliği, çerezlerin üçüncü taraf alanlardan gelen isteklerde gönderilip gönderilmeyeceğini belirler. Üç ayarı vardır:
- **Strict**: Çerezin üçüncü taraf isteklerinde gönderilmesini kısıtlar. - **Strict**: Çerezin üçüncü taraf isteklerinde gönderilmesini kısıtlar.
- **Lax**: Çerezin üçüncü taraf web siteleri tarafından başlatılan GET istekleri ile gönderilmesine izin verir. - **Lax**: Çerezin üçüncü taraf web siteleri tarafından başlatılan GET istekleri ile gönderilmesine izin verir.
- **None**: Çerezin herhangi bir üçüncü taraf alanından gönderilmesine izin verir. - **None**: Çerezin herhangi bir üçüncü taraf alanından gönderilmesine izin verir.
Çerezleri yapılandırırken, bu nitelikleri anlamak, farklı senaryolar arasında beklenildiği gibi davranmalarını sağlamaya yardımcı olabilir. Çerezleri yapılandırırken, bu özellikleri anlamak, farklı senaryolar arasında beklenildiği gibi davranmalarını sağlamaya yardımcı olabilir.
| **İstek Türü** | **Örnek Kod** | **Çerezler Ne Zaman Gönderilir** | | **İstek Türü** | **Örnek Kod** | **Çerezler Ne Zaman Gönderilir** |
| --------------- | ------------------------------- | --------------------------------- | | ---------------- | ---------------------------------- | --------------------- |
| Bağlantı | \<a href="...">\</a> | NotSet\*, Lax, None | | Bağlantı | \<a href="...">\</a> | NotSet\*, Lax, None |
| Önceden Yükleme | \<link rel="prerender" href=".."/> | NotSet\*, Lax, None | | Önceden Yükleme | \<link rel="prerender" href=".."/> | NotSet\*, Lax, None |
| Form GET | \<form method="GET" action="..."> | NotSet\*, Lax, None | | Form GET | \<form method="GET" action="..."> | NotSet\*, Lax, None |
| Form POST | \<form method="POST" action="..."> | NotSet\*, None | | Form POST | \<form method="POST" action="..."> | NotSet\*, None |
| iframe | \<iframe src="...">\</iframe> | NotSet\*, None | | iframe | \<iframe src="...">\</iframe> | NotSet\*, None |
| AJAX | $.get("...") | NotSet\*, None | | AJAX | $.get("...") | NotSet\*, None |
| Resim | \<img src="..."> | NetSet\*, None | | Resim | \<img src="..."> | NetSet\*, None |
Tablo [Invicti](https://www.netsparker.com/blog/web-security/same-site-cookie-attribute-prevent-cross-site-request-forgery/) kaynağından alınmış ve hafifçe değiştirilmiştir.\ Tablo [Invicti](https://www.netsparker.com/blog/web-security/same-site-cookie-attribute-prevent-cross-site-request-forgery/) kaynağından alınmış ve biraz değiştirilmiştir.\
_**SameSite**_ niteliğine sahip bir çerez, **CSRF saldırılarını azaltacaktır**. _**SameSite**_ özelliğine sahip bir çerez, **CSRF saldırılarını azaltacaktır**.
**\*Chrome80 (şub/2019) itibarıyla, bir çerez için varsayılan davranış, çerez samesite** **nitelikleri yoksa lax** olacaktır ([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 (şub/2019) itibarıyla, bir çerez için varsayılan davranış, çerez samesite** **özelliği yoksa lax olacaktır** ([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/)).\
Bu değişiklik uygulandıktan sonra, **SameSite** **politikası olmayan çerezler Chrome'da** **ilk 2 dakika boyunca None** olarak **değerlendirilecek ve ardından üst düzey çapraz site POST isteği için Lax** olarak değerlendirilecektir. Bu değişiklik uygulandıktan sonra, **SameSite** **politikası olmayan çerezler Chrome'da** **ilk 2 dakika boyunca None olarak, ardından üst düzey çapraz site POST isteği için Lax olarak** **işlenecektir.**
## Çerez Bayrakları ## Çerez Bayrakları
@ -58,11 +58,11 @@ Bu, **istemcinin** çereze erişimini engeller (Örneğin **Javascript** ile: `d
#### **Aşmalar** #### **Aşmalar**
- Eğer sayfa, bir isteğin yanıtı olarak çerezleri **gönderiyorsa** (örneğin bir **PHPinfo** sayfasında), XSS'i kötüye kullanarak bu sayfaya bir istek göndermek ve **çerezleri yanıtından çalmak** mümkündür (örneği kontrol edin [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/)). - Eğer sayfa, bir isteğin yanıtı olarak çerezleri **gönderiyorsa** (örneğin bir **PHPinfo** sayfasında), XSS'i kötüye kullanarak bu sayfaya bir istek göndermek ve yanıtından **çerezleri çalmak** mümkündür (örneği kontrol edin [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/)).
- Bu, **TRACE** **HTTP** istekleri ile aşılabilir çünkü sunucudan gelen yanıt, gönderilen çerezleri yansıtacaktır. Bu teknik **Cross-Site Tracking** olarak adlandırılır. - Bu, **TRACE** **HTTP** istekleri ile aşılabilir çünkü sunucudan gelen yanıt, gönderilen çerezleri yansıtır (bu HTTP yöntemi mevcutsa). Bu teknik **Cross-Site Tracking** olarak adlandırılır.
- Modern tarayıcılar, JS'den TRACE isteği göndermeye izin vermeyerek bu tekniği engeller. Ancak, IE6.0 SP2'ye `TRACE` yerine `\r\nTRACE` göndererek bazı aşmalar bulunmuştur. - Modern tarayıcılar, JS'den TRACE isteği göndermeye izin vermeyerek bu tekniği engeller. Ancak, IE6.0 SP2'ye `\r\nTRACE` göndermek gibi belirli yazılımlarda bazı aşmalar bulunmuştur.
- Diğer bir yol, tarayıcıların sıfır/günlük açıklarını istismar etmektir. - Diğer bir yol, tarayıcıların sıfır/günlük açıklarını istismar etmektir.
- Bir Çerez Jar taşma saldırısı gerçekleştirerek **HttpOnly çerezlerini** **mak** mümkündür: - Bir Çerez Jar taşma saldırısı gerçekleştirerek **HttpOnly çerezlerini** **üst üste yazmak** mümkündür:
{{#ref}} {{#ref}}
cookie-jar-overflow.md cookie-jar-overflow.md
@ -82,18 +82,18 @@ cookie-jar-overflow.md
- `secure` bayrağı ile ayarlanmalıdır. - `secure` bayrağı ile ayarlanmalıdır.
- HTTPS ile güvence altına alınmış bir sayfadan gelmelidir. - HTTPS ile güvence altına alınmış bir sayfadan gelmelidir.
- Bir alan belirtmeleri yasaktır, bu da alt alanlara iletimlerini engeller. - Alt alan adlarına iletilmesini engellemek için bir alan belirtmeleri yasaktır.
- Bu çerezlerin yolu `/` olarak ayarlanmalıdır. - Bu çerezlerin yolu `/` olarak ayarlanmalıdır.
`__Host-` ile başlayan çerezlerin süper alanlara veya alt alanlara gönderilmesine izin verilmediğini belirtmek önemlidir. Bu kısıtlama, uygulama çerezlerini izole etmeye yardımcı olur. Bu nedenle, tüm uygulama çerezleri için `__Host-` ön ekinin kullanılması, güvenliği ve izolasyonu artırmak için iyi bir uygulama olarak kabul edilebilir. `__Host-` ile başlayan çerezlerin süper alan adlarına veya alt alan adlarına gönderilmesine izin verilmediğini belirtmek önemlidir. Bu kısıtlama, uygulama çerezlerini izole etmeye yardımcı olur. Bu nedenle, tüm uygulama çerezleri için `__Host-` ön ekinin kullanılması, güvenliği ve izolasyonu artırmak için iyi bir uygulama olarak kabul edilebilir.
### Çerezleri Üzerine Yazma ### Çerezleri Üst Üste Yazma
Dolayısıyla, `__Host-` ile başlayan çerezlerin korunmasından biri, alt alanlardan üzerine yazılmalarını engellemektir. Örneğin [**Cookie Tossing saldırılarını**](cookie-tossing.md) önlemek. [**Cookie Crumbles: Unveiling Web Session Integrity Vulnerabilities**](https://www.youtube.com/watch?v=F_wAzF4a7Xg) ([**makale**](https://www.usenix.org/system/files/usenixsecurity23-squarcina.pdf)) konuşmasında, alt alanlardan `__HOST-` ile başlayan çerezlerin ayarlanmasının, örneğin başına veya sonuna "=" ekleyerek, ayrıştırıcıyı kandırarak mümkün olduğu sunulmuştur: Dolayısıyla, `__Host-` ile başlayan çerezlerin korunmasından biri, alt alan adlarından üst üste yazılmalarını engellemektir. Örneğin [**Cookie Tossing saldırılarını**](cookie-tossing.md) önlemek. [**Cookie Crumbles: Web Oturum Bütünlüğü Açıklarını Ortaya Çıkarma**](https://www.youtube.com/watch?v=F_wAzF4a7Xg) ([**makale**](https://www.usenix.org/system/files/usenixsecurity23-squarcina.pdf)) konuşmasında, çerez adının başına veya başına ve sonuna `=` ekleyerek alt alan adlarından \_\_HOST- ile başlayan çerezlerin ayarlanmasının mümkün olduğu sunulmuştur:
<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>
Ya da PHP'de çerez adının başına **başka karakterler ekleyerek**, bunların **alt çizgi** karakterleri ile **değiştirileceği** mümkün olmuştur, bu da `__HOST-` çerezlerini üzerine yazmaya olanak tanır: Ya da PHP'de çerez adının başına **diğer karakterler ekleyerek**, bu karakterlerin **alt çizgi** karakterleri ile değiştirilmesi sağlanarak `__HOST-` çerezlerinin üst üste yazılması mümkündür:
<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 @@ Ya da PHP'de çerez adının başına **başka karakterler ekleyerek**, bunları
### Çerezleri Çözme ve Manipüle Etme ### Çerezleri Çözme ve Manipüle Etme
Çerezlerde gömülü hassas veriler her zaman incelenmelidir. Base64 veya benzeri formatlarda kodlanmış çerezler genellikle çözülebilir. Bu zafiyet, saldırganların çerezin içeriğini değiştirmesine ve değiştirilmiş verilerini çereze geri kodlayarak diğer kullanıcıları taklit etmesine olanak tanır. Çerezlerde gömülü hassas veriler her zaman incelenmelidir. Base64 veya benzeri formatlarda kodlanmış çerezler genellikle çözülebilir. Bu zafiyet, saldırganların çerezin içeriğini değiştirmesine ve diğer kullanıcıları taklit etmek için değiştirilmiş verilerini çereze geri kodlamasına olanak tanır.
### Oturum Ele Geçirme ### Oturum Ele Geçirme
@ -111,9 +111,9 @@ Bu saldırı, bir kullanıcının çerezini çalarak uygulama içindeki hesabın
### Oturum Sabitleme ### Oturum Sabitleme
Bu senaryoda, bir saldırgan bir kurbanı belirli bir çerezi kullanarak oturum açmaya kandırır. Uygulama oturum açıldığında yeni bir çerez atamazsa, saldırgan, orijinal çerezi elinde bulundurarak kurbanı taklit edebilir. Bu teknik, kurbanın saldırgan tarafından sağlanan bir çerezle oturum açmasına dayanır. Bu senaryoda, bir saldırgan bir kurbanı belirli bir çerezi kullanarak giriş yapmaya kandırır. Uygulama giriş yapıldığında yeni bir çerez atamazsa, saldırgan, orijinal çerezi elinde bulundurarak kurbanı taklit edebilir. Bu teknik, kurbanın saldırgan tarafından sağlanan bir çerezle giriş yapmasına dayanır.
Eğer bir **alt alanında XSS bulduysanız** veya **bir alt alanı kontrol ediyorsanız**, okuyun: Eğer bir **alt alan adında XSS bulduysanız** veya **bir alt alan adını kontrol ediyorsanız**, okuyun:
{{#ref}} {{#ref}}
cookie-tossing.md cookie-tossing.md
@ -121,9 +121,9 @@ cookie-tossing.md
### Oturum Bağışı ### Oturum Bağışı
Burada, saldırgan kurbanı saldırganın oturum çerezini kullanmaya ikna eder. Kurban, kendi hesabında oturum açtığını düşünerek, istemeden saldırganın hesabı bağlamında eylemler gerçekleştirir. Burada, saldırgan kurbanı saldırganın oturum çerezini kullanmaya ikna eder. Kurban, kendi hesabında oturum açtığını düşünerek, saldırganın hesabı bağlamında istemeden eylemler gerçekleştirir.
Eğer bir **alt alanında XSS bulduysanız** veya **bir alt alanı kontrol ediyorsanız**, okuyun: Eğer bir **alt alan adında XSS bulduysanız** veya **bir alt alan adını kontrol ediyorsanız**, okuyun:
{{#ref}} {{#ref}}
cookie-tossing.md cookie-tossing.md
@ -141,13 +141,13 @@ Bu saldırı, oturum açmış bir kullanıcının, şu anda kimlik doğrulaması
### Boş Çerezler ### Boş Çerezler
(Başka detaylar için [orijinal araştırmaya](https://blog.ankursundara.com/cookie-bugs/) bakın) Tarayıcılar, isim olmadan çerez oluşturulmasına izin verir, bu da JavaScript ile şu şekilde gösterilebilir: (Başka ayrıntılar için [orijinal araştırmaya](https://blog.ankursundara.com/cookie-bugs/) bakın) Tarayıcılar, isim olmadan çerez oluşturulmasına izin verir, bu da JavaScript ile şu şekilde gösterilebilir:
```js ```js
document.cookie = "a=v1" 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"
``` ```
Gönderilen çerez başlığındaki sonuç `a=v1; test value; b=v2;` şeklindedir. İlginç bir şekilde, bu, boş bir isim çerezi ayarlandığında çerezlerin manipüle edilmesine olanak tanır; bu, boş çerezi belirli bir değere ayarlayarak diğer çerezleri kontrol etme potansiyeli taşır: Gönderilen çerez başlığındaki sonuç `a=v1; test value; b=v2;`. İlginç bir şekilde, bu, boş bir isim çerezi ayarlandığında çerezlerin manipüle edilmesine olanak tanır ve boş çerezi belirli bir değere ayarlayarak diğer çerezleri kontrol etme potansiyeli taşır:
```js ```js
function setCookie(name, value) { function setCookie(name, value) {
document.cookie = `${name}=${value}` document.cookie = `${name}=${value}`
@ -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
``` ```
Bu, tarayıcının her web sunucusu tarafından `a` adında ve `b` değerinde bir çerez olarak yorumlanan bir çerez başlığı göndermesine yol açar. Bu, tarayıcının her web sunucusu tarafından `a` adlı ve `b` değerine sahip bir çerez olarak yorumlanan bir çerez başlığı göndermesine yol açar.
#### Chrome Hatası: Unicode Yedek Kod Noktası Sorunu #### Chrome Hatası: Unicode Yedek Kod Noktası Sorunu
@ -167,37 +167,37 @@ Bu, `document.cookie`'nin boş bir dize döndürmesiyle sonuçlanır ve kalıcı
#### Ayrıştırma Sorunlarından Kaynaklanan Cookie Smuggling #### Ayrıştırma Sorunlarından Kaynaklanan Cookie Smuggling
(Daha fazla ayrıntı için [orijinal araştırmaya](https://blog.ankursundara.com/cookie-bugs/) bakın) Java (Jetty, TomCat, Undertow) ve Python (Zope, cherrypy, web.py, aiohttp, bottle, webob) gibi birkaç web sunucusu, eski RFC2965 desteği nedeniyle çerez dizelerini yanlış işler. Çift tırnak içinde bir çerez değeri, normalde anahtar-değer çiftlerini ayırması gereken noktalı virgüller içerse bile, tek bir değer olarak okunur: (Daha fazla detay için [orijinal araştırmaya](https://blog.ankursundara.com/cookie-bugs/) bakın) Java (Jetty, TomCat, Undertow) ve Python (Zope, cherrypy, web.py, aiohttp, bottle, webob) gibi birkaç web sunucusu, eski RFC2965 desteği nedeniyle çerez dizelerini yanlış işler. Bir çerez değeri çift tırnak içinde olsa bile, genellikle anahtar-değer çiftlerini ayıran noktalı virgüller içerse bile, bunu tek bir değer olarak okurlar:
``` ```
RENDER_TEXT="hello world; JSESSIONID=13371337; ASDF=end"; RENDER_TEXT="hello world; JSESSIONID=13371337; ASDF=end";
``` ```
#### Cookie Injection Vulnerabilities #### Cookie Injection Vulnerabilities
(Check further details in the[original research](https://blog.ankursundara.com/cookie-bugs/)) Sunucuların çerezleri yanlış analiz etmesi, özellikle Undertow, Zope ve Python'un `http.cookie.SimpleCookie` ve `http.cookie.BaseCookie` kullananlar, çerez enjeksiyon saldırıları için fırsatlar yaratır. Bu sunucular, yeni çerezlerin başlangıcını düzgün bir şekilde ayırt edemez, bu da saldırganların çerezleri taklit etmesine olanak tanır: (Check further details in the[original research](https://blog.ankursundara.com/cookie-bugs/)) Sunucuların çerezleri yanlış analiz etmesi, özellikle Undertow, Zope ve Python'un `http.cookie.SimpleCookie` ve `http.cookie.BaseCookie` kullananlar, çerez enjeksiyonu saldırıları için fırsatlar yaratır. Bu sunucular, yeni çerezlerin başlangıcını düzgün bir şekilde ayırt edemez, bu da saldırganların çerezleri taklit etmesine olanak tanır:
- Undertow, alıntılanmış bir değerden hemen sonra bir yeni çerez bekler, noktalı virgül olmadan. - Undertow, alıntılanmış bir değerden hemen sonra bir yeni çerez bekler, noktalı virgül olmadan.
- Zope, bir sonraki çerezi analiz etmeye başlamak için bir virgül arar. - Zope, bir sonraki çerezi analiz etmeye başlamak için bir virgül arar.
- Python'un çerez sınıfları, bir boşluk karakterinde analiz yapmaya başlar. - Python'un çerez sınıfları, bir boşluk karakterinde analiz yapmaya başlar.
Bu zafiyet, çerez tabanlı CSRF korumasına dayanan web uygulamalarında özellikle tehlikelidir, çünkü saldırganların taklit CSRF-token çerezlerini enjekte etmesine olanak tanır ve bu da güvenlik önlemlerinin aşılmasına yol açabilir. Sorun, Python'un tekrar eden çerez adlarını ele almasıyla daha da kötüleşir; burada son gerçekleşme, önceki olanları geçersiz kılar. Ayrıca, `__Secure-` ve `__Host-` çerezleri için güvensiz bağlamlarda endişeleri artırır ve çerezlerin taklit edilme eğiliminde olan arka uç sunuculara iletilmesi durumunda yetkilendirme aşımına yol açabilir. Bu zafiyet, çerez tabanlı CSRF korumasına dayanan web uygulamalarında özellikle tehlikelidir, çünkü saldırganların taklit CSRF-token çerezlerini enjekte etmesine olanak tanır ve bu da güvenlik önlemlerinin aşılmasına yol açabilir. Sorun, Python'un tekrar eden çerez adlarını ele almasıyla daha da kötüleşir; burada son gerçekleşme, önceki olanları geçersiz kılar. Ayrıca, güvensiz bağlamlarda `__Secure-` ve `__Host-` çerezleri için endişeleri artırır ve çerezlerin taklit edilme eğiliminde olan arka uç sunuculara iletilmesi durumunda yetkilendirme aşımına yol açabilir.
### Cookies $version ### Cookies $version
#### WAF Bypass #### WAF Bypass
According to [**this blogpost**](https://portswigger.net/research/bypassing-wafs-with-the-phantom-version-cookie), arka ucu çerezi analiz etmek için eski bir mantığı kullanmaya zorlamak amacıyla çerez niteliği **`$Version=1`** kullanmak mümkün olabilir, bu da **RFC2109**'dan kaynaklanmaktadır. Ayrıca, **`$Domain`** ve **`$Path`** gibi diğer değerler, çerezi kullanarak arka ucun davranışını değiştirmek için kullanılabilir. [**bu blog yazısına**](https://portswigger.net/research/bypassing-wafs-with-the-phantom-version-cookie) göre, **RFC2109** nedeniyle arka ucun çerezi analiz etmek için eski bir mantığı kullanmasını sağlamak için çerez niteliği **`$Version=1`** kullanmak mümkün olabilir. Ayrıca, **`$Domain`** ve **`$Path`** gibi diğer değerler, çerezin arka uç üzerindeki davranışını değiştirmek için kullanılabilir.
#### Cookie Sandwich Attack #### Cookie Sandwich Attack
According to [**this blogpost**](https://portswigger.net/research/stealing-httponly-cookies-with-the-cookie-sandwich-technique) çerez sandviçi tekniğini kullanarak HttpOnly çerezlerini çalmak mümkündür. İşte gereksinimler ve adımlar: [**bu blog yazısına**](https://portswigger.net/research/stealing-httponly-cookies-with-the-cookie-sandwich-technique) göre, HttpOnly çerezlerini çalmak için çerez sandviçi tekniğini kullanmak mümkündür. İşte gereksinimler ve adımlar:
- Görünüşte gereksiz bir **çerezin yanıtta yansıtıldığı** bir yer bulun - Görünüşte işe yaramaz bir **çerezin yanıtta yansıtıldığı** bir yer bulun
- **Değeri `1` olan `$Version`** adında bir çerez oluşturun (bunu JS'den bir XSS saldırısı ile yapabilirsiniz) daha spesifik bir yol ile böylece başlangıç konumunu alır (bazı çerçeve dilleri bu adımı gerektirmez) - **Değeri `1` olan `$Version`** adında bir çerez oluşturun (bunu JS'den bir XSS saldırısı ile yapabilirsiniz) ve başlangıç konumunu almak için daha spesifik bir yol belirleyin (Python gibi bazı çerçeveler bu adımı gerektirmez)
- **Yansıtılan çerezi oluşturun** ve değeri **açık çift tırnak** bırakan ve belirli bir yol ile böylece önceki çerezin (`$Version`) ardından çerez veritabanında konumlanmasını sağlayın - **Yansıtılan çerezi oluşturun** ve değeri **açık çift tırnak** bırakan ve önceki çerezin (`$Version`) ardından çerez veritabanında konumlanacak şekilde spesifik bir yol ile
- Sonra, meşru çerez sırada bir sonraki olacaktır - Sonra, meşru çerez sırada bir sonraki olacaktır
- **Değeri içinde çift tırnağı kapatan bir sahte çerez oluşturun** - **Değeri içinde çift tırnağı kapatan bir sahte çerez oluşturun**
Bu şekilde, kurban çerezi yeni çerez versiyon 1 içinde sıkışır ve her yansıtıldığında yansıtılır. Bu şekilde, kurban çerezi yeni çerez versiyon 1 içinde sıkışacak ve her yansıtıldığında yansıtılacaktır.
```javascript ```javascript
document.cookie = `$Version=1;`; document.cookie = `$Version=1;`;
document.cookie = `param1="start`; document.cookie = `param1="start`;
@ -210,18 +210,18 @@ document.cookie = `param2=end";`;
Önceki bölüme bakın. Önceki bölüme bakın.
#### Alıntı dizgesi kodlaması ile değer analizini atlama #### Bypassing value analysis with quoted-string encoding
Bu ayrıştırma, çerezler içindeki kaçış karakterlerini çözmek için kaçış değerlerini geri almayı gösterir, böylece "\a" "a" olur. Bu, WAF'ları atlamak için yararlı olabilir: Bu ayrıştırma, çerezler içindeki kaçış karakterlerini çözmek için kaçış değerlerini geri almayı gösterir, böylece "\a" "a" olur. Bu, WAF'ları aşmak için yararlı olabilir:
- `eval('test') => yasak` - `eval('test') => forbidden`
- `"\e\v\a\l\(\'\t\e\s\t\'\)" => izin verildi` - `"\e\v\a\l\(\'\t\e\s\t\'\)" => allowed`
#### Çerez adı kara liste atlaması #### Bypassing cookie-name blocklists
RFC2109'da **virgülün çerez değerleri arasında ayırıcı olarak kullanılabileceği** belirtilmiştir. Ayrıca **eşittir işaretinden önce ve sonra boşluklar ve sekmeler eklemek mümkündür**. Bu nedenle, `$Version=1; foo=bar, abc = qux` gibi bir çerez, `"foo":"bar, admin = qux"` çerezini oluşturmaz, bunun yerine `foo":"bar"` ve `"admin":"qux"` çerezlerini oluşturur. İki çerez nasıl oluşturulduğuna ve admin'in eşittir işaretinden önce ve sonra boşluğun nasıl kaldırıldığına dikkat edin. RFC2109'da **virgülün çerez değerleri arasında ayırıcı olarak kullanılabileceği** belirtilmiştir. Ayrıca **eşittir işaretinden önce ve sonra boşluklar ve sekmeler eklemek mümkündür**. Bu nedenle, `$Version=1; foo=bar, abc = qux` gibi bir çerez, `"foo":"bar, admin = qux"` çerezini oluşturmaz, bunun yerine `foo":"bar"` ve `"admin":"qux"` çerezlerini oluşturur. İki çerez nasıl oluşturulduğuna ve admin'in eşittir işaretinden önce ve sonra boşluğun nasıl kaldırıldığına dikkat edin.
#### Çerez bölme ile değer analizini atlama #### Bypassing value analysis with cookie splitting
Son olarak, farklı arka kapılar, farklı çerez başlıklarında geçen farklı çerezleri bir dize içinde birleştirebilir: Son olarak, farklı arka kapılar, farklı çerez başlıklarında geçen farklı çerezleri bir dize içinde birleştirebilir:
``` ```
@ -242,16 +242,16 @@ Resulting cookie: name=eval('test//, comment') => allowed
#### **Temel kontroller** #### **Temel kontroller**
- **Çerez** her seferinde **giriş yaptığınızda** **aynıdır**. - **Çerez** her seferinde **giriş yaptığınızda** **aynıdır**.
- Çıkış yapın ve aynı çerezi kullanmaya çalışın. - Çıkış yapın ve aynı çerezi kullanmayı deneyin.
- Aynı çerezi kullanarak 2 cihazda (veya tarayıcıda) aynı hesaba giriş yapmayı deneyin. - Aynı çerezi kullanarak 2 cihazda (veya tarayıcıda) aynı hesaba giriş yapmayı deneyin.
- Çerezde herhangi bir bilgi olup olmadığını kontrol edin ve bunu değiştirmeye çalışın. - Çerezde herhangi bir bilgi olup olmadığını kontrol edin ve bunu değiştirmeyi deneyin.
- Neredeyse aynı kullanıcı adıyla birkaç hesap oluşturmaya çalışın ve benzerlikleri görüp göremediğinizi kontrol edin. - Neredeyse aynı kullanıcı adıyla birkaç hesap oluşturmayı deneyin ve benzerlikleri görüp göremediğinizi kontrol edin.
- Varsa "**beni hatırla**" seçeneğini kontrol edin ve nasıl çalıştığını görün. Varsa ve hassas olabileceğini düşünüyorsanız, her zaman başka bir çerez olmadan **beni hatırla** çerezini kullanın. - Varsa "**beni hatırla**" seçeneğini kontrol edin ve nasıl çalıştığını görün. Varsa ve savunmasız olabileceğini düşünüyorsanız, her zaman başka bir çerez olmadan **beni hatırla** çerezini kullanın.
- Önceki çerezin, şifreyi değiştirdikten sonra bile çalışıp çalışmadığını kontrol edin. - Önceki çerezin şifreyi değiştirdikten sonra bile çalışıp çalışmadığını kontrol edin.
#### **Gelişmiş çerez saldırıları** #### **Gelişmiş çerez saldırıları**
Çerez giriş yaptığınızda aynı (veya neredeyse aynı) kalıyorsa, bu muhtemelen çerezin hesabınızdaki bir alanla (muhtemelen kullanıcı adıyla) ilişkili olduğu anlamına gelir. O zaman şunları yapabilirsiniz: Çerez giriş yaptığınızda aynı (veya neredeyse aynı) kalıyorsa, bu muhtemelen çerezin hesabınızdaki bazı alanlarla (muhtemelen kullanıcı adıyla) ilişkili olduğu anlamına gelir. O zaman şunları yapabilirsiniz:
- Çok **benzer** kullanıcı adlarına sahip birçok **hesap** oluşturmaya çalışın ve algoritmanın nasıl çalıştığını **tahmin** etmeye çalışın. - Çok **benzer** kullanıcı adlarına sahip birçok **hesap** oluşturmaya çalışın ve algoritmanın nasıl çalıştığını **tahmin** etmeye çalışın.
- **Kullanıcı adını brute force** etmeyi deneyin. Eğer çerez yalnızca kullanıcı adınız için bir kimlik doğrulama yöntemi olarak kaydediliyorsa, o zaman "**Bmin**" kullanıcı adıyla bir hesap oluşturabilir ve çerezin her bir **bitini brute force** edebilirsiniz çünkü deneyeceğiniz çerezlerden biri "**admin**"e ait olan olacaktır. - **Kullanıcı adını brute force** etmeyi deneyin. Eğer çerez yalnızca kullanıcı adınız için bir kimlik doğrulama yöntemi olarak kaydediliyorsa, o zaman "**Bmin**" kullanıcı adıyla bir hesap oluşturabilir ve çerezin her bir **bitini brute force** edebilirsiniz çünkü deneyeceğiniz çerezlerden biri "**admin**"e ait olan olacaktır.
@ -279,13 +279,13 @@ Bu yürütme, içinde **user=administrator** dizesi bulunan çerezi doğru bir
**CBC-MAC** **CBC-MAC**
Belki bir çerez bazı değerlere sahip olabilir ve CBC kullanılarak imzalanabilir. O zaman, değerin bütünlüğü, aynı değerle CBC kullanılarak oluşturulan imzadır. IV olarak null vektör kullanılması önerildiğinden, bu tür bir bütünlük kontrolü savunmasız olabilir. Belki bir çerez bazı değerlere sahip olabilir ve CBC kullanılarak imzalanabilir. O zaman, değerin bütünlüğü, aynı değerle CBC kullanılarak oluşturulan imzadır. IV olarak null bir vektör kullanılması önerildiğinden, bu tür bir bütünlük kontrolü savunmasız olabilir.
**Saldırı** **Saldırı**
1. Kullanıcı adı **administ** için imzayı al = **t** 1. Kullanıcı adı **administ** için imzayı al = **t**
2. Kullanıcı adı **rator\x00\x00\x00 XOR t** için imzayı al = **t'** 2. Kullanıcı adı **rator\x00\x00\x00 XOR t** için imzayı al = **t'**
3. Çerezde değeri **administrator+t'** olarak ayarla (**t'** geçerli bir imza olacaktır **(rator\x00\x00\x00 XOR t) XOR t** = **rator\x00\x00\x00** 3. Çerezde değeri **administrator+t'** olarak ayarla (**t'** geçerli bir imza olacaktır **(rator\x00\x00\x00 XOR t) XOR t** = **rator\x00\x00\x00**)
**ECB** **ECB**
@ -294,11 +294,11 @@ Giriş yaptığınızda aldığınız çerez her zaman aynı olmalıdır.
**Nasıl tespit edilir ve saldırılır:** **Nasıl tespit edilir ve saldırılır:**
Neredeyse aynı verilere sahip 2 kullanıcı oluşturun (kullanıcı adı, şifre, e-posta vb.) ve verilen çerez içinde bir desen keşfetmeye çalışın. Neredeyse aynı verilere sahip 2 kullanıcı oluşturun (kullanıcı adı, şifre, e-posta vb.) ve verilen çerez içinde bazı desenleri keşfetmeye çalışın.
Örneğin "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" adında bir kullanıcı oluşturun ve çerezde herhangi bir desen olup olmadığını kontrol edin (çünkü ECB her bloğu aynı anahtar ile şifrelediğinden, kullanıcı adı şifrelendiğinde aynı şifrelenmiş baytlar görünebilir). Örneğin "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" adında bir kullanıcı oluşturun ve çerezde herhangi bir desen olup olmadığını kontrol edin (çünkü ECB her bloğu aynı anahtarla şifrelediğinden, kullanıcı adı şifrelendiğinde aynı şifrelenmiş baytlar görünebilir).
Kullanılan bir bloğun boyutunda bir desen olmalıdır. Yani, bir grup "a" nın nasıl şifrelendiğini bilerek bir kullanıcı adı oluşturabilirsiniz: "a"*(bloğun boyutu)+"admin". Ardından, çerezden bir "a" bloğunun şifrelenmiş desenini silebilirsiniz. Ve "admin" kullanıcı adının çerezine sahip olacaksınız. Kullanılan bir bloğun boyutunda bir desen olmalıdır. Yani, bir grup "a"nın nasıl şifrelendiğini bilerek bir kullanıcı adı oluşturabilirsiniz: "a"*(blok boyutu)+"admin". Ardından, çerezden bir "a" bloğunun şifrelenmiş desenini silebilirsiniz. Ve "admin" kullanıcı adının çerezine sahip olacaksınız.
## Referanslar ## Referanslar

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);
});
}
})(); })();