Kamu baru sadar ada patch keamanan kritis yang telat diaplikasikan. Pertanyaannya: apakah situsmu sudah dieksploitasi sebelum patch terpasang? Jawabannya ada di log server, file system, dan database. Pola access log mencurigakan, file PHP baru di folder uploads, admin user asing di tabel wp_users, serta row mencurigakan di wp_options adalah Indicators of Compromise (IoC) yang bisa kamu grep dalam hitungan menit. Artikel ini memberikan daftar konkret command grep, query SQL, dan pola anomali yang langsung bisa kamu jalankan sekarang.

Pukul 02:14 dini hari. Kamu scroll timeline X sambil ngopi. Tiba-tiba muncul notifikasi WordPress Security Team: CVE-202X-XXXXX dengan skor CVSS 9.8, critical, unauthenticated remote code execution. Plugin yang kamu pakai. Patch dirilis 14 jam yang lalu.
Jantungmu deg-degan. Bukan karena aplikasi patch-nya sulit, tapi karena satu pertanyaan yang lebih mengerikan: apakah situsku sudah dijebol dalam 14 jam terakhir? Atau lebih parah lagi, apakah eksploitasi sudah terjadi berminggu-minggu sebelum CVE ini dipublikasikan?
Di sinilah konsep Indicators of Compromise (IoC) masuk. IoC adalah artefak digital yang tertinggal setelah sistemmu dikompromikan. Bentuknya bisa berupa log entry, file mencurigakan, entri database asing, sampai perubahan konfigurasi yang tidak kamu lakukan. Artikel ini akan membongkar pola-pola IoC paling konkret yang bisa kamu grep, find, dan SELECT dalam 30 menit ke depan.
Pola Access Log: Jejak Kaki Penyerang di Web Server
Access log web server adalah tempat pertama yang harus kamu periksa. Setiap HTTP request tersimpan di sini dengan format timestamp, IP, method, path, status code, dan user-agent. Kalau penyerang mengeksploitasi celah lewat HTTP, jejaknya pasti ada di sini.
Sebelum mulai, pastikan kamu tahu lokasi access log-mu. Untuk Nginx, biasanya di /var/log/nginx/access.log. Untuk Apache, umumnya di /var/log/apache2/access.log atau /var/log/httpd/access_log. Kalau pakai aaPanel, cek di /www/wwwlogs/.
1. POST Request ke Path yang Tidak Punya Form
Ini adalah IoC paling sering terlewat. Banyak admin hanya mencari request ke path yang sudah dikenal mencurigakan. Padahal, penyerang modern mengeksploitasi endpoint sah yang menerima POST, lalu menyuntikkan payload lewat parameter yang tidak divalidasi.
Coba jalankan command ini untuk melihat POST request dalam 72 jam terakhir:
grep -E '"POST' /var/log/nginx/access.log | awk '{print $7, $1, $4}' | sort | uniq -c | sort -rn | head -30
Outputnya akan menunjukkan endpoint mana yang paling sering kena POST. Cari anomali seperti: POST ke /wp-json/jetpack/v4/ dari IP yang tidak kamu kenali, POST ke file PHP di folder /wp-content/uploads/, POST ke /xmlrpc.php dengan request body besar (di atas 5KB), atau POST ke plugin endpoint yang seharusnya cuma dipakai admin.
Kalau kamu menemukan POST request ke file PHP di folder uploads, itu adalah backdoor yang sudah terpasang. Penyerang mengunggah file PHP, lalu mengaksesnya untuk mengeksekusi perintah. Segera cek file tersebut.
2. User-Agent Abnormal atau Sama Sekali Kosong
Exploit script otomatis jarang menyertakan User-Agent yang normal. Mereka sering menggunakan string default dari library seperti python-requests/2.x, curl/7.x, Go-http-client, atau yang lebih mencurigakan: User-Agent kosong.
Jalankan ini untuk mengidentifikasi User-Agent abnormal yang mengakses endpoint sensitif:
grep -E '(wp-admin|wp-login|xmlrpc|wp-json)' /var/log/nginx/access.log | awk -F'"' '{print $6}' | sort | uniq -c | sort -rn | head -20
Selain itu, cek juga request tanpa User-Agent sama sekali. Banyak scanner exploit yang tidak menyertakan header ini:
grep -E '(wp-admin|wp-login|xmlrpc|wp-json)' /var/log/nginx/access.log | grep -v 'Mozilla' | grep -v 'Chrome' | grep -v 'Safari' | grep -v 'Firefox' | tail -50

3. Spike Request ke Endpoint Spesifik dalam Waktu Sempit
Penyerang yang baru menemukan exploit sering menjalankan mass scanning. Mereka akan mengirim puluhan hingga ratusan request ke endpoint yang sama dalam hitungan detik, biasanya untuk mencari parameter yang bisa diinjeksi.
Cek pola ini dengan menghitung request per menit dari IP yang sama:
awk '{print $1, substr($4,2,14)}' /var/log/nginx/access.log | sort | uniq -c | awk '$1 > 20 {print}' | head -30
Kalau kamu melihat satu IP mengirim lebih dari 20 request per menit ke endpoint plugin-mu, itu adalah indikasi kuat automated exploitation attempt. Apalagi kalau IP tersebut berasal dari VPS provider seperti DigitalOcean, Vultr, atau AWS EC2, bukan dari residential ISP.
File System Changes: Backdoor yang Siap Dipakai Lagi
Access log menunjukkan cara masuk. Tapi yang lebih berbahaya adalah apa yang ditinggalkan setelah penyerang masuk. Backdoor adalah potongan kode yang disembunyikan di file sistem untuk memberi akses permanen, meskipun celah aslinya sudah ditambal.
4. File PHP Baru di Folder Uploads
Folder /wp-content/uploads/ seharusnya hanya berisi media: gambar, video, PDF. Kalau ada file .php di sana, itu hampir pasti backdoor. Penyerang suka menanam file di sini karena folder ini writable dan jarang diaudit.
Jalankan command berikut untuk menemukan semua file PHP di folder uploads:
find /path/to/wp-content/uploads -name "*.php" -type f -ls
Jangan berhenti di ekstensi .php saja. Penyerang sering mengganti ekstensi untuk menghindari deteksi. Cari juga file dengan ekstensi ganda, pola mencurigakan seperti .php5, .phtml, .shtml, atau .phar:
find /path/to/wp-content/uploads -type f \( -name "*.php*" -o -name "*.phtml" -o -name "*.shtml" -o -name "*.phar" \) -ls
Ini juga saatnya menjalankan wp core verify-checksums via WP-CLI. Command ini membandingkan setiap file core WordPress dengan checksum resmi dari wordpress.org. File core yang berubah tapi bukan karena update adalah tanda pasti infiltrasi.
5. Timestamp File yang Tidak Masuk Akal
Penyerang sering lupa (atau tidak peduli) untuk mengubah timestamp file backdoor agar sesuai dengan file asli. Akibatnya, file backdoor memiliki modification time yang mencurigakan, misalnya pukul 3 pagi atau tanggal yang tidak cocok dengan riwayat update-mu.
Cari file yang dimodifikasi dalam 7 hari terakhir, lalu urutkan berdasarkan tanggal:
find /path/to/wordpress -type f -mtime -7 -printf '%Tc %p\n' | sort -k1 -k2 | tail -30
Perhatikan file-file di folder wp-admin, wp-includes, dan root WordPress yang termodifikasi di luar jadwal update normal. File seperti wp-config.php, .htaccess, atau index.php yang berubah tanpa sepengetahuanmu adalah IoC paling serius.
Khusus untuk .htaccess, periksa isinya. Penyerang sering menyisipkan rewrite rules yang redirect traffic ke situs lain, atau aturan yang mengizinkan eksekusi PHP di folder tertentu:
grep -i -E '(RewriteRule|AddType|AddHandler|php_value|auto_prepend_file|auto_append_file)' /path/to/wordpress/.htaccess
6. File Tersembunyi dengan Nama Menipu
Backdoor sering disembunyikan dengan nama yang meniru file sistem sah. Contoh klasik: wp-config.php.bak, index.php.old, admin.php, config.php, atau file dengan nama acak seperti a7b3c.php. Teknik lain: file disembunyikan dengan awalan dot (.backdoor.php) agar tidak muncul di ls biasa.
Jalankan ini untuk menemukan file tersembunyi dan file dengan ekstensi ganda:
find /path/to/wordpress -name ".*" -type f -not -name ".htaccess" -not -path "*/\.git/*" -ls
find /path/to/wordpress -type f -name "*.*.*" -ls

Database Anomalies: Bukti yang Tidak Bisa Dihapus dari Access Log
Access log bisa dirotasi. File backdoor bisa dihapus. Tapi database adalah tempat penyimpanan paling persisten. Penyerang yang sudah mendapat akses hampir selalu meninggalkan jejak di database, baik berupa user baru, perubahan konfigurasi, atau data yang disisipkan.
7. Admin User Baru yang Tidak Kamu Kenal
Ini adalah IoC paling jelas dan paling sering ditemukan. Penyerang membuat user administrator baru dengan nama samar supaya tetap bisa masuk meskipun password user asli sudah diganti.
Query ini menampilkan semua user dengan role administrator, diurutkan berdasarkan tanggal registrasi:
SELECT u.ID, u.user_login, u.user_email, u.user_registered,
GROUP_CONCAT(m.meta_key, ':', m.meta_value SEPARATOR ' | ') AS meta
FROM wp_users u
LEFT JOIN wp_usermeta m ON u.ID = m.user_id
WHERE m.meta_key = 'wp_capabilities' AND m.meta_value LIKE '%administrator%'
GROUP BY u.ID
ORDER BY u.user_registered DESC;
Kalau kamu melihat user dengan nama seperti support_sys, wp_manager, admin_login, atau kombinasi acak huruf dan angka yang registrasinya baru-baru ini, itu adalah backdoor account. Hapus user tersebut, tapi catat dulu semua detailnya sebagai bukti forensik.
Row Misterius di wp_options
Tabel wp_options adalah target favorit karena menyimpan konfigurasi inti WordPress. Penyerang sering menyisipkan opsi dengan nama yang meniru prefix asli, atau menambahkan active_plugins palsu untuk memuat malware.
Cek opsi yang baru ditambahkan atau dimodifikasi:
SELECT option_name, LENGTH(option_value) AS val_size
FROM wp_options
WHERE option_name NOT LIKE 'wp_%'
AND option_name NOT LIKE 'siteurl'
AND option_name NOT LIKE 'blogname'
AND option_name NOT LIKE 'widget_%'
AND option_name NOT LIKE 'theme_mods_%'
AND LENGTH(option_value) > 100
ORDER BY option_id DESC
LIMIT 30;
Opsi dengan nilai besar (ratusan atau ribuan karakter) dan nama yang tidak standar patut dicurigai. Penyerang sering menyimpan encoded payload di sini yang akan dieksekusi oleh backdoor di file system.
Plugin atau Tema yang Tiba-Tiba Aktif
Penyerang kadang mengunggah plugin berbahaya lewat dashboard WordPress setelah mendapat akses admin. Plugin ini biasanya memiliki nama generik seperti maintenance, backup, atau security-fix.
Cek daftar plugin yang baru diinstal:
ls -lt /path/to/wp-content/plugins/ | head -20
Cocokkan dengan apa yang terlihat di dashboard. Kalau ada folder plugin yang tidak kamu kenal, cek isinya. Plugin backdoor biasanya berisi satu file PHP dengan nama yang meniru plugin sah, tapi isinya adalah eval(), base64_decode(), atau system().
Framework Cepat: Daftar Grep dan Query yang Langsung Kamu Jalankan
Berikut adalah checklist ringkas yang bisa kamu salin-tempel ke terminal dan MySQL client. Jalankan berurutan, catat setiap temuan mencurigakan, lalu tindak lanjuti dengan investigasi lebih dalam.
- Access Log:
grep -E '"POST' access.log | awk '{print $7, $1}' | sort | uniq -c | sort -rn | head -20 - PHP di Uploads:
find wp-content/uploads -name "*.php" -type f -ls - File Baru 7 Hari:
find . -type f -mtime -7 -printf '%Tc %p\n' | sort -r | head -40 - Core Integrity:
wp core verify-checksums(via WP-CLI) - User Admin Baru:
SELECT * FROM wp_users ORDER BY ID DESC LIMIT 5; - wp_options Mencurigakan:
SELECT option_name FROM wp_options WHERE option_name NOT LIKE 'wp_%' AND option_name NOT LIKE 'siteurl' AND option_name NOT LIKE 'blogname' AND option_name NOT LIKE 'widget_%' AND option_name NOT LIKE 'theme_mods_%' ORDER BY option_id DESC LIMIT 20; - Modified .htaccess:
grep -i -E '(AddType|AddHandler|auto_prepend|auto_append|RewriteRule.*http)' .htaccess - Backdoor Signature:
grep -rln -E '(eval\s*\(|base64_decode|system\s*\(|shell_exec|passthru)' wp-content/ --include="*.php" | grep -v vendor | grep -v node_modules

Yang Jarang Dibahas: Timeline Correlation
Di sinilah admin biasa berhenti dan incident responder profesional melanjutkan. Menemukan satu IoC itu bagus. Tapi mengkorelasikan beberapa IoC dalam satu timeline adalah kunci untuk memahami seberapa dalam eksploitasi yang terjadi.
Begini cara kerjanya. Kamu menemukan tiga jenis IoC yang berbeda: satu dari access log (POST request mencurigakan ke plugin endpoint), satu dari file system (file PHP baru di uploads), dan satu dari database (admin user baru). Sekarang, gabungkan timestamp ketiganya.
Misalnya: access log menunjukkan POST request dari IP 45.xxx ke /wp-json/plugin/v1/upload pada 02:14:32. File PHP baru di uploads memiliki timestamp 02:14:35 (3 detik kemudian). Admin user baru di tabel wp_users memiliki user_registered pada 02:15:10 (38 detik kemudian).
Ini adalah rantai serangan yang sempurna: penyerang mengeksploitasi celah upload di plugin (IoC 1), berhasil mengunggah backdoor (IoC 2), lalu mengeksekusi backdoor untuk membuat akun admin (IoC 3). Dengan korelasi ini, kamu sekarang tahu persis: titik masuknya, file yang harus dihapus, akun yang harus dihapus, dan IP penyerang yang bisa kamu blokir dan laporkan ke penyedia VPS-nya.
Tanpa korelasi, kamu hanya melihat tiga artefak terpisah tanpa memahami hubungannya. Dengan korelasi, kamu bisa merekonstruksi langkah demi langkah apa yang dilakukan penyerang, dan yang lebih penting, memastikan tidak ada backdoor lain yang tersisa.
Tools seperti GoAccess atau pipeline ELK (Elasticsearch, Logstash, Kibana) bisa membantu mengkorelasikan log dari berbagai sumber secara otomatis. Tapi untuk investigasi cepat, spreadsheet sederhana dengan kolom timestamp, source, dan deskripsi IoC sudah cukup efektif.
Kesimpulan: Forensik Log Itu Keahlian Wajib, Bukan Opsional
Patch keamanan memang penting. Tapi patch hanya melindungi dari serangan setelah patch terpasang. Untuk serangan yang terjadi sebelum patch, satu-satunya cara untuk tahu adalah lewat log forensik. Tidak ada plugin yang bisa memberi jawaban pasti selain kamu sendiri yang turun ke terminal dan database.
Jadikan checklist di artikel ini sebagai SOP setiap kali ada CVE kritis yang memengaruhi stack-mu. Jangan menunggu Google memberi label merah atau pelanggan komplain. Dengan 30 menit forensik proaktif, kamu bisa tidur nyenyak karena tahu persis apakah situsmu aman atau tidak. Dan kalau ternyata ada indikasi eksploitasi, kamu sudah setengah jalan dalam proses incident response.
Baca juga panduan kami tentang 8 langkah darurat pemulihan WordPress kena hack untuk melanjutkan proses recovery setelah IoC ditemukan, dan panduan monitoring keamanan real-time supaya ke depannya kamu tidak perlu melakukan forensik manual lagi.
FAQ: Indicators of Compromise dan Log Forensics
Q: Apa bedanya Indicators of Compromise (IoC) dengan Indicators of Attack (IoA)?A: IoC adalah bukti bahwa sistem sudah dikompromikan, seperti backdoor file atau admin user asing. IoA adalah sinyal bahwa serangan sedang berlangsung, seperti lonjakan failed login atau scanning vulnerability. Dalam konteks forensik pre-patch, kamu mencari IoC untuk mengonfirmasi apakah eksploitasi benar-benar terjadi. IoA berguna untuk deteksi real-time, sedangkan IoC berguna untuk investigasi retrospektif.
Q: Berapa lama access log biasanya disimpan sebelum dirotasi?
A: Standar umum adalah 14-30 hari untuk shared hosting dan VPS murah. Tapi ini sangat tergantung konfigurasi logrotate di server. Kalau kamu sudah telat lebih dari 30 hari sejak patch dirilis, kemungkinan access log-nya sudah terhapus. Karena itu, jangan tunda forensik. Segera setelah tahu ada CVE kritis, langsung amankan log sebelum dirotasi. Untuk ke depannya, pertimbangkan menyimpan log terpusat di layanan seperti Loggly, Papertrail, atau Graylog dengan retention minimal 90 hari.
Q: Gimana kalau aku menemukan IoC tapi nggak yakin cara membersihkannya?
A: Jangan panik dan jangan hapus sembarangan. Langkah pertama: offline-kan situs lewat maintenance mode atau DNS. Kedua: backup semua log, file, dan database ke penyimpanan lokal sebagai bukti forensik. Ketiga: ikuti checklist di artikel pemulihan total WordPress kena hack. Keempat: kalau kamu nggak yakin bisa membersihkan sendiri, sewa profesional incident response. Biaya $500-$2000 untuk IR profesional jauh lebih murah daripada kerusakan reputasi dan kehilangan data.
Q: Apakah ada cara otomatis untuk mendeteksi IoC tanpa grep manual?
A: Ada. Plugin seperti Wordfence dan Sucuri punya scanner malware yang bisa mendeteksi sebagian besar backdoor signature. Tapi scanner otomatis hanya mendeteksi pattern yang sudah dikenal (signature-based). Untuk zero-day exploit atau backdoor custom, deteksi manual lewat grep dan query SQL masih jadi standar emas. Kombinasikan keduanya: jalankan scanner otomatis dulu, lalu verifikasi manual untuk anomali yang mungkin terlewat.
Q: Apakah menghapus IoC (file backdoor, user admin asing) berarti situsku sudah bersih?
A: Belum tentu. Penyerang yang sudah masuk bisa saja menanam multiple backdoor di lokasi berbeda sebagai cadangan. Menghapus satu backdoor tanpa mengaudit seluruh sistem hanya memberi rasa aman palsu. Setelah membersihkan IoC yang ditemukan, lakukan full audit: cek semua file baru dalam 30 hari terakhir, cek cron jobs mencurigakan, cek semua user dengan akses admin, dan reset semua kredensial. Idealnya, restore dari backup bersih dan bangun ulang dari awal.



