Panduan ini untuk pengembang dan admin server situs OPD yang di-deface atau disisipi konten judi online (judol). Contoh perintah memakai Linux dengan docroot /var/www/situs; sesuaikan path, nama pengguna, nama database, dan lokasi log dengan server Anda. Kerjakan berurutan: amankan bukti dulu, baru bersihkan.
1. Kenali tandanya
Sisipan judol biasanya dibuat supaya tidak terlihat oleh pengelola. Pola yang sering ditemukan:
- Cloaking berdasarkan user agent: konten judi hanya dikirim bila pengunjungnya Googlebot, bingbot, atau Google-InspectionTool, sedangkan browser biasa melihat situs normal.
- Blok HTML tersembunyi dengan
display:noneatau posisi di luar layar, berisi deretan tautan ke situs judi. - Sisipan teks atau tautan sesudah tag
</html>di akhir halaman. - Widget
custom_html(WordPress) atau blok teks di footer yang memuat penanda jaringan tautan berbayar sepertiMagenetMonetization. - Pemilik atau pengguna asing di Google Search Console, biasanya akun Gmail acak, disertai berkas verifikasi
google*.htmlbaru di docroot. - Berkas
.phpasing di folder upload atau folder aset, kadang bernama mirip berkas sah sepertisitemap.phpatau*.min.php. .htaccessdiubah dengan aturanRewriteCond %{HTTP_USER_AGENT}atau%{HTTP_REFERER}.- Pengunjung HP atau pengunjung yang datang dari Google dialihkan ke situs judi, sementara pengunjung desktop yang mengetik alamat langsung tidak.
Cek dari luar dengan membandingkan respons untuk browser biasa, Googlebot, dan HP:
SITUS=https://namadomain.kutaitimurkab.go.id/
POLA='slot|gacor|togel|toto|maxwin|casino|judi|rtp'
# Jumlah baris yang cocok: browser biasa vs Googlebot
curl -s -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" "$SITUS" | grep -ciE "$POLA"
curl -s -A "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" "$SITUS" | grep -ciE "$POLA"
# Pengalihan untuk pengunjung HP yang datang dari Google
curl -s -o /dev/null -w '%{http_code} %{redirect_url}\n' \
-A "Mozilla/5.0 (Linux; Android 14; Mobile) AppleWebKit/537.36 Chrome/130.0 Mobile Safari/537.36" \
-e "https://www.google.com/" "$SITUS"
# Apa pun yang ada sesudah </html>
curl -s -A "Googlebot" "$SITUS" | sed -n '/<\/html>/,$p' | head -20
Sebagian cloaker memeriksa alamat IP Google, sehingga curl dengan user agent Googlebot tetap menerima halaman normal. Cara yang paling bisa diandalkan adalah Inspeksi URL di Google Search Console: jalankan tes URL live, lalu buka HTML hasil crawl untuk melihat halaman persis seperti yang diterima Googlebot.
2. Amankan bukti sebelum mengubah apa pun
Berkas asing, log, dan waktu modifikasinya diperlukan untuk menemukan jalan masuk. Kalau langsung dihapus, celahnya sulit ditemukan dan situs akan dibobol lagi. Simpan salinan bukti di luar server setelah selesai.
B=/root/bukti-$(date +%Y%m%d-%H%M)
mkdir -p "$B"
# Salinan docroot lengkap dengan atribut waktu dan kepemilikan
tar --numeric-owner -cpzf "$B/docroot.tgz" -C /var/www situs
# Daftar berkas dengan mtime, ctime, dan pemilik
find /var/www/situs -type f -printf '%TY-%Tm-%Td %TH:%TM %CY-%Cm-%Cd %CH:%CM %u %p\n' | sort > "$B/daftar-berkas.txt"
# Log akses dan error, termasuk arsip .gz
cp -a /var/log/nginx /var/log/httpd /var/log/apache2 "$B/" 2>/dev/null
# Dump database
mysqldump --single-transaction nama_db > "$B/db.sql"
# Hash agar keutuhan bukti bisa dibuktikan
find "$B" -type f ! -name SHA256SUMS -exec sha256sum {} + > "$B/SHA256SUMS"
Di server cPanel, log akses per domain ada di /usr/local/apache/domlogs/ dan arsipnya di /home/<akun>/logs/.
3. Isolasi situs
- Pasang halaman maintenance dengan kode HTTP 503 atau nonaktifkan virtual host selama pembersihan. Kode 503 memberi tahu Google bahwa situs sedang tidak tersedia sementara. Contoh nginx:
return 503;di blok server situs, lalunginx -t && systemctl reload nginx. - Di cPanel/WHM, akun hosting dapat di-suspend dari WHM.
- Blokir IP pelaku yang ditemukan di log (langkah 4) di firewall server.
4. Cari webshell dan berkas yang diubah
D=/var/www/situs
# Berkas yang berubah dalam 14 hari terakhir (mtime)
find "$D" -type f -mtime -14 -printf '%TY-%Tm-%Td %TH:%TM %p\n' | sort
# ctime ikut dicek, karena mtime mudah dipalsukan dengan touch
find "$D" -type f -ctime -14 -printf '%CY-%Cm-%Cd %CH:%CM %p\n' | sort
# Skrip di folder upload dan aset (isinya seharusnya gambar, dokumen, CSS, JS)
find "$D" \( -path '*/upload*' -o -path '*/images/*' -o -path '*/assets/*' -o -path '*/storage/*' -o -path '*/media/*' \) \
-type f \( -iname '*.php*' -o -iname '*.phtml' -o -iname '*.phar' -o -iname '*.cgi' -o -iname '*.pl' -o -iname '*.py' \)
# Pola kode yang lazim di webshell dan backdoor
grep -rlE --include='*.php' --include='*.phtml' --include='*.inc' \
'eval\s*\(|assert\s*\(|base64_decode\s*\(|gzinflate\s*\(|str_rot13\s*\(|shell_exec|passthru|proc_open|\$_(POST|GET|REQUEST|COOKIE)\s*\[[^]]*\]\s*\(' "$D"
# Berkas verifikasi Google, tag verifikasi, dan .htaccess yang membaca user agent/referer
find "$D" -maxdepth 3 -name 'google*.html'
grep -rl 'google-site-verification' "$D" --include='*.php' --include='*.html'
grep -rn --include='.htaccess' -iE 'HTTP_USER_AGENT|HTTP_REFERER|googlebot' "$D"
# Penanda sisipan judol
grep -rliE 'MagenetMonetization|slot ?gacor|maxwin|togel' "$D" --include='*.php' --include='*.html' --include='*.js'
Hasil grep perlu diperiksa satu per satu, karena library sah juga memakai base64_decode atau eval. Hasil -ctime juga ikut menampilkan berkas yang baru di-chmod atau dipulihkan dari backup. Kalau kode dideploy dari git, jalankan git status --porcelain di docroot: berkas yang tidak dikenal git patut dicurigai.
Untuk WordPress, jalankan WP-CLI sebagai pengguna pemilik situs:
cd /var/www/situs
wp core verify-checksums
wp plugin verify-checksums --all
wp user list --role=administrator --fields=ID,user_login,user_email,user_registered
wp option get widget_custom_html | grep -iE 'magenet|slot|togel'
wp db search 'MagenetMonetization' --all-tables
Cari jalan masuk di log akses. Permintaan pertama pelaku ke webshell, atau POST ke fitur unggah tepat sebelum webshell muncul, biasanya menunjukkan celahnya:
L=/var/log/nginx/access.log
# Siapa saja yang mengakses webshell yang ditemukan (ganti nama berkasnya)
zgrep -hE 'sitemap\.php|nama-shell\.php' $L* | awk '{print $1}' | sort | uniq -c | sort -rn
# POST ke skrip di folder upload atau aset
zgrep -hE '"POST [^"]*/(uploads?|images|assets|storage)/[^" ]*\.(php|phtml|phar)' $L*
# Seluruh POST dari satu IP pelaku, urut waktu (ganti IP contoh)
zgrep -h '^203\.0\.113\.10 ' $L* | grep '"POST' | sort -k4 | head -50
5. Periksa akun, cron, kunci SSH, dan persistensi
# Pengguna terbaru di database CMS (contoh WordPress; sesuaikan prefiks tabel)
mysql nama_db -e "SELECT ID,user_login,user_email,user_registered FROM wp_users ORDER BY user_registered DESC LIMIT 20;"
# Cron semua pengguna dan cron sistem
for u in $(cut -d: -f1 /etc/passwd); do crontab -l -u "$u" 2>/dev/null | sed "s/^/$u: /"; done
ls -la /etc/cron.d /etc/cron.hourly /var/spool/cron* 2>/dev/null
# Kunci SSH yang diizinkan
for f in /root/.ssh/authorized_keys /home/*/.ssh/authorized_keys; do echo "== $f"; cat "$f" 2>/dev/null; done
# Persistensi di direktori home dan berkas startup shell
ls -la /home/*/.config /home/*/.local/bin 2>/dev/null
grep -nE 'base64|curl|wget|nohup|GS_|/dev/tcp' /home/*/.bashrc /home/*/.profile /root/.bashrc 2>/dev/null
# Proses non-root yang menyamar dengan nama proses kernel, dan koneksi keluar
ps -eo user=,pid=,args= | awk '$1!="root" && $3 ~ /^\[/'
ss -tupn
Backdoor seperti gsocket sering ditaruh di ~/.config atau ~/.local, dijalankan ulang lewat cron berisi perintah base64, dan memakai nama proses palsu dalam kurung siku. Proses kernel asli selalu milik root.
6. Ganti semua kredensial
- Semua akun admin CMS. Hapus akun yang tidak dikenal sesudah dicatat sebagai bukti.
- Password database. Anggap isi
.env,wp-config.php, atau berkas konfigurasi database lain sudah dibaca pelaku. - Token API, kunci SMTP, dan secret aplikasi. Di WordPress, ganti salt dengan
wp config shuffle-salts.APP_KEYLaravel perlu direncanakan karena data yang dienkripsi dengan kunci lama ikut terdampak. - Akun FTP, SSH, dan panel hosting (cPanel/WHM/Plesk).
- Email pengelola yang terhubung dengan akun-akun di atas.
Ganti kredensial sesudah webshell dibersihkan atau di server pengganti. Password baru yang dibuat selagi webshell masih aktif dapat langsung dibaca lagi.
7. Tutup celahnya
- Update CMS, plugin, tema, framework, dan versi PHP. Cocokkan versi yang terpasang dengan katalog CVE.
- Celah yang sering ditemukan: fitur unggah tanpa validasi tipe berkas, rute admin yang bisa dibuka tanpa login, plugin usang, mode debug yang aktif di produksi, dan password admin lemah.
- Larang eksekusi skrip di folder upload. Taruh aturannya di konfigurasi virtual host;
.htaccessdi folder upload bisa ditimpa pelaku.
# nginx: di dalam blok server, letakkan SEBELUM location ~ \.php$
location ~* /(uploads?|storage|media)/.*\.(php|phtml|phar|pl|py|cgi)$ { deny all; }
# Apache: di <Directory> folder upload pada konfigurasi virtual host
<FilesMatch "\.(php|phtml|phar|pl|py|cgi)$">
Require all denied
</FilesMatch>
8. Pulihkan dari backup bersih
- Tentukan waktu masuk pertama dari log dan daftar berkas, lalu pilih backup yang dibuat sebelum waktu itu.
- Utamakan memasang ulang kode dari sumber resmi (paket CMS, plugin, dan tema asli, atau repository git), lalu salin hanya konten seperti gambar dan dokumen setelah dipindai dengan perintah di langkah 4.
- Periksa database hasil restore untuk posting, halaman, widget, dan opsi yang memuat tautan judi.
- Jalankan ulang pemeriksaan langkah 1 dan 4 pada hasil pemulihan sebelum situs dibuka kembali.
9. Bersihkan Google Search Console
- Buka Setelan > Pengguna dan izin. Catat lalu hapus pengguna dan pemilik yang ditunjuk yang tidak dikenal (panduan Google: mengelola pemilik, pengguna, dan izin).
- Pemilik terverifikasi yang asing hanya bisa dihapus dengan membuang token verifikasinya: berkas
google*.html, tag metagoogle-site-verification, atau record TXT di DNS. Selama token masih ada, pemilik itu tetap bisa kembali. - Untuk URL judi yang masih muncul di hasil pencarian, pastikan URL tersebut sudah mengembalikan 404 atau 410, lalu ajukan lewat alat Penghapusan. Penghapusan ini sementara, berlaku sekitar enam bulan (panduan alat Penghapusan).
- Buka laporan Masalah keamanan dan Tindakan manual. Bila ada temuan, ajukan peninjauan setelah situs bersih.
- Pakai Inspeksi URL pada halaman utama dan halaman penting, periksa HTML hasil crawl, lalu pilih Minta pengindeksan.
- Hapus sitemap asing yang didaftarkan pelaku dan kirim ulang sitemap yang sah.
10. Pantau ulang
- Ulangi pengecekan langkah 1 dan pencarian
site:setiap hari selama dua minggu, lalu setiap minggu. - Pantau log akses untuk permintaan ke nama berkas webshell yang sudah ditemukan. Pelaku biasanya mencoba lagi dari IP lain.
- Simpan hash berkas situs yang sudah bersih sebagai baseline dan bandingkan secara berkala:
# Baseline sesudah situs bersih
find /var/www/situs -type f -exec sha256sum {} + | sort -k2 > /root/baseline-situs.sha256
# Berkas yang berubah atau hilang dibanding baseline
sha256sum -c --quiet /root/baseline-situs.sha256
# Berkas baru yang belum ada di baseline
comm -13 <(awk '{print $2}' /root/baseline-situs.sha256 | sort) <(find /var/www/situs -type f | sort)
Laporkan
Laporkan ke KUTIM-CSIRT lewat /lapor dengan kategori Penyisipan Konten Judi/SEO (Judol), atau Perusakan Situs (Defacement) bila tampilan diganti, dengan tingkat keparahan Tinggi atau Kritis. Sertakan daftar berkas mencurigakan beserta waktu modifikasinya, IP yang muncul di log, dan langkah yang sudah dikerjakan. Formulir hanya menerima gambar dan PDF (maksimal 5 berkas, masing-masing 5 MB). Untuk log dan berkas bukti, tulis di uraian bahwa bukti tersedia, atau kirim terenkripsi ke csirt@kutaitimurkab.go.id mengikuti panduan PGP.