Introduction
In this report, we will examine a critical SQL Injection vulnerability detected in the "Movie Rating System 1.0" application and how this vulnerability can be escalated to a Remote Code Execution (RCE) attack. This attack allows an unauthenticated attacker to gain full control over the server.
Vulnerability Analysis
SQL Injection Point
Upon examining the movie_details.php file, which displays movie details, we see that the id parameter is included directly in the SQL query without sufficient security measures.
// Vulnerable Code in movie_details.php
if(isset($_GET['id'])){
$qry = $conn->query("SELECT * FROM `movie_list` where id = '{$_GET['id']}'");
// ...
}

In the code above, the $_GET['id'] variable is added to the query without any sanitization or use of prepared statements. This allows an attacker to manipulate the SQL query and perform unauthorized operations on the database.
Exploit Development
The exploit (exploit.py) I developed to escalate this vulnerability to an RCE attack follows these steps:
-
Target and Page Detection: The exploit takes the target URL, finds the "Movies" page, and reaches a valid movie detail page (movie_details.php?id=...).
-
Path Disclosure:
The attacker adds a single quote (') character to the id parameter to generate an SQL syntax error. If error messages are enabled on the server (display_errors = On), PHP returns a warning message containing the full physical path of the file on the server (e.g., C:\xampp\htdocs\movie\movie_details.php). The exploit parses this error to obtain the web root directory (C:/xampp/htdocs/movie/).
-
SQL to RCE (INTO OUTFILE):
After obtaining the file path, MySQL's INTO OUTFILE feature is used to write a malicious PHP file to the server.
Payload Logic Used:
-1881' OR 1881=1881 LIMIT 0,1 INTO OUTFILE 'C:/xampp/htdocs/movie/shell.php' LINES TERMINATED BY 0x3c3f70687020... -- -
Here, the LINES TERMINATED BY clause is critical. Normally, while the query result is written to the file, the hex-encoded PHP shell code (<?php ... system($cmd); ... ?>) determined by the attacker is added to the end of the lines. Thus, the created file becomes an executable PHP file by the server.
Note: For this attack to be successful, the database user must have the FILE privilege, and the secure_file_priv setting must allow file writing.
-
Code Execution:
After the file is successfully created, the exploit sends an HTTP request to the shell.php file and executes the whoami command to verify its authority on the system.
Remediation
To fix this critical vulnerability, the following steps must be applied:
1. Use Prepared Statements:
Instead of directly concatenating user inputs in SQL queries, Prepared Statements must be used.
Secure Code Example:
$stmt = $conn->prepare("SELECT * FROM `movie_list` where id = ?");
$stmt->bind_param("s", $_GET['id']);
$stmt->execute();
$qry = $stmt->get_result();
2. Hide Error Messages:
Displaying PHP error messages to the user in the production environment should be prevented. display_errors should be set to Off in the php.ini file.
3. Restrict Database Privileges:
The database user used by the web application should not be granted high privileges such as FILE. Only necessary privileges like SELECT, INSERT, UPDATE, DELETE should be defined.
4. secure_file_priv Setting:
In the MySQL configuration, the secure_file_priv setting should be directed to a secure directory outside the web root or set to NULL to restrict file operations.
Giriş
Bu raporda, "Movie Rating System 1.0" uygulamasında tespit edilen kritik bir SQL Enjeksiyonu (SQL Injection) zafiyetini ve bu zafiyetin Uzaktan Kod Yürütme (RCE) saldırısına nasıl dönüştürülebileceğini inceleyeceğiz. Bu saldırı, kimliği doğrulanmamış bir saldırganın sunucu üzerinde tam kontrol sağlamasına olanak tanır.
Zafiyet Analizi
SQL Enjeksiyonu Noktası
Uygulamanın film detaylarını gösteren movie_details.php dosyasını incelediğimizde, id parametresinin yeterli güvenlik önlemleri alınmadan doğrudan SQL sorgusuna dahil edildiğini görüyoruz.
// movie_details.php içindeki Zafiyetli Kod
if(isset($_GET['id'])){
$qry = $conn->query("SELECT * FROM `movie_list` where id = '{$_GET['id']}'");
// ...
}

Yukarıdaki kodda, $_GET['id'] değişkeni herhangi bir temizleme işleminden geçirilmeden veya hazırlanmış ifadeler (prepared statements) kullanılmadan sorguya eklenmektedir. Bu durum, saldırganın SQL sorgusunu manipüle etmesine ve veritabanı üzerinde yetkisiz işlemler yapmasına olanak tanır.
Exploit Geliştirme
Bu zafiyeti bir RCE saldırısına dönüştürmek için geliştirdiğim exploit (exploit.py) şu adımları izlemektedir:
-
Hedef ve Sayfa Tespiti: Exploit, hedef URL'yi alır ve "Movies" sayfasını bularak geçerli bir film detay sayfasına (movie_details.php?id=...) ulaşır.
-
Yol İfşası (Path Disclosure):
Saldırgan, id parametresine tek tırnak (') karakteri ekleyerek bir SQL sözdizimi hatası oluşturur. Eğer sunucuda hata mesajları açıksa (display_errors = On), PHP bir uyarı mesajı döndürür ve bu mesaj dosyanın sunucu üzerindeki tam fiziksel yolunu (örn. C:\xampp\htdocs\movie\movie_details.php) içerir. Exploit, bu hatayı ayrıştırarak web kök dizinini (C:/xampp/htdocs/movie/) elde eder.
-
SQL'den RCE'ye (INTO OUTFILE):
Dosya yolunu elde ettikten sonra, MySQL'in INTO OUTFILE özelliği kullanılarak sunucuya kötü amaçlı bir PHP dosyası yazılır.
Kullanılan Payload Mantığı:
-1881' OR 1881=1881 LIMIT 0,1 INTO OUTFILE 'C:/xampp/htdocs/movie/shell.php' LINES TERMINATED BY 0x3c3f70687020... -- -
Burada LINES TERMINATED BY ifadesi kritik öneme sahiptir. Normalde sorgu sonucu dosyaya yazılırken, satır sonlarına saldırganın belirlediği hex kodlanmış PHP shell kodu (<?php ... system($cmd); ... ?>) eklenir. Böylece oluşturulan dosya, sunucu tarafından çalıştırılabilir bir PHP dosyası haline gelir.
Not: Bu saldırının başarılı olabilmesi için veritabanı kullanıcısının FILE yetkisine sahip olması ve secure_file_priv ayarının dosya yazmaya izin vermesi gerekmektedir.
-
Kod Yürütme:
Dosya başarıyla oluşturulduktan sonra, exploit shell.php dosyasına bir HTTP isteği gönderir ve whoami komutunu çalıştırarak sistem üzerindeki yetkisini doğrular.
Çözüm ve Kapatma
Bu kritik zafiyeti gidermek için aşağıdaki adımlar uygulanmalıdır:
1. Prepared Statements Kullanımı:
SQL sorgularında kullanıcı girdilerini doğrudan birleştirmek yerine, mutlaka Hazırlanmış İfadeler (Prepared Statements) kullanılmalıdır.
Güvenli Kod Örneği:
$stmt = $conn->prepare("SELECT * FROM `movie_list` where id = ?");
$stmt->bind_param("s", $_GET['id']);
$stmt->execute();
$qry = $stmt->get_result();
2. Hata Mesajlarını Gizleme:
Canlı ortamda (production) PHP hata mesajlarının kullanıcıya gösterilmesi engellenmelidir. php.ini dosyasında display_errors = Off olarak ayarlanmalıdır.
3. Veritabanı Yetkilerini Kısıtlama:
Web uygulamasının kullandığı veritabanı kullanıcısına FILE gibi yüksek yetkiler verilmemelidir. Sadece gerekli olan SELECT, INSERT, UPDATE, DELETE yetkileri tanımlanmalıdır.
4. secure_file_priv Ayarı:
MySQL yapılandırmasında secure_file_priv ayarı, web kök dizini dışında güvenli bir dizine yönlendirilmeli veya NULL olarak ayarlanarak dosya işlemleri kısıtlanmalıdır.