Bali, Indonesia
Insights

Hosting Diblokir karena Spam Padahal Tidak Kirim Email? Lacak Skrip PHP-nya

November 1, 2026
0:00
Akun hosting tiba-tiba di-suspend, atau IP server masuk blacklist dengan alasan mengirim spam. Pemilik situs bingung karena merasa tidak pernah mengirim email massal. Paling banter situsnya cuma punya form kontak. Pada banyak kasus memang bukan dia yang mengirim, tapi skrip PHP di akunnya. Bisa backdoor yang ditanam penyerang, bisa juga form yang disalahgunakan bot. Exim untungnya mencatat cukup banyak jejak untuk melacak dari mana email itu berasal. Di meja support, kalimat yang paling sering muncul dari pelanggan di situasi ini adalah "saya tidak kirim apa-apa". Itu biasanya jujur. Masalahnya, server tidak peduli siapa yang merasa mengirim. Yang dicatat adalah proses mana yang memanggil mail server. Jadi kita mulai dari log, bukan dari asumsi.
Tidak semua laporan spam berarti server kita yang mengirim. Kadang orang luar hanya memalsukan alamat pengirim (spoofing), lalu bounce-nya membanjiri inbox pemilik domain. Kalau itu yang terjadi, mencari skrip PHP di server cuma buang waktu. Cara membedakannya lewat header email sudah dibahas di Membaca Header Email untuk Membedakan Spoofing dan Akun yang Dibobol. Cek cepat dari sisi server: lihat jumlah pesan di queue dengan exim -bpc. Queue adalah antrean pesan yang belum terkirim. Angka yang jauh di atas kebiasaan server, apalagi kalau terus naik, tanda kuat ada pengiriman keluar yang tidak wajar. Spam massal biasanya menumpuk di queue karena banyak tujuan menolak atau menunda (defer) pesannya. Kalau queue normal dan log tidak menunjukkan lonjakan pengiriman dari akun itu, kemungkinan besar masalahnya spoofing atau IP yang dipakai bersama akun lain. Kalau queue penuh, lanjut ke langkah berikutnya.
Setiap pesan yang diterima Exim dicatat di log utama dengan tanda <=. Di baris itu ada beberapa field yang menentukan arah investigasi:
  • A=dovecot_login:... atau A=dovecot_plain:... berarti pengirim login SMTP dengan akun email. Kalau spam datang lewat jalur ini, yang bocor adalah password akun email, bukan file PHP.
  • P=local dengan U=namauser berarti pesan dikirim lewat binary sendmail di server itu sendiri. Fungsi mail() di PHP, cron job, dan skrip CLI masuk lewat jalur ini.
Pemisahan ini penting karena perbaikannya beda total. Akun email yang dibobol cukup ganti password dan cek perangkat penggunanya. Skrip PHP berarti ada file di webroot yang perlu ditemukan. Contoh format output untuk jalur skrip lokal kira-kira seperti ini (ilustrasi, bukan log asli):
TEXT
2026-01-01 00:00:00 cwd=/home/contohuser/public_html/wp-content/uploads/2020/05 3 args: /usr/sbin/sendmail -t -i
2026-01-01 00:00:00 1aBcDe-000AbC-Xy <= [email protected] U=contohuser P=local S=2048
Baris pertama mencatat argumen pemanggilan sendmail beserta direktori kerjanya. Baris kedua mencatat pesan yang diterima. Dari dua baris ini kita sudah tahu user sistemnya (contohuser) dan, lebih penting lagi, dari direktori mana proses itu berjalan.
cwd adalah current working directory, yaitu direktori tempat proses berada saat memanggil sendmail. Untuk PHP yang dijalankan lewat web, nilainya biasanya direktori tempat file skrip berada. Itu sebabnya field ini sangat membantu: kita tidak perlu menebak di antara ribuan file. Field ini tidak selalu ada. Exim hanya mencatatnya kalau opsi log_selector menyertakan +arguments. Di server cPanel opsi ini umumnya aktif. Di instalasi Exim manual, belum tentu. Cek dulu sebelum menarik kesimpulan dari log yang kosong:
BASH
# Lihat apakah +arguments ada di log_selector
exim -bP log_selector

# Hitung direktori asal pengiriman, yang paling sering di bawah
# (path log ini untuk cPanel; sesuaikan dengan distro)
grep 'cwd=' /var/log/exim_mainlog | grep -v '/var/spool' | awk -F'cwd=' '{print 2}' | awk '{print1}' | sort | uniq -c | sort -n | tail -20
Baris dengan /var/spool dibuang karena itu proses Exim sendiri, misalnya saat memproses queue atau membuat bounce. Bukan skrip user. Hasilnya perlu dibaca dengan kepala dingin. Ada beberapa pola yang sering mengecoh: Direktori seperti wp-admin atau folder plugin dengan jumlah kecil biasanya notifikasi wajar, misalnya email reset password atau pesanan toko online. Yang dicari adalah volume yang tidak masuk akal untuk ukuran situsnya. cwd=/home/namauser saja (tanpa public_html) sering berasal dari cron job, karena cron biasanya berjalan dari home directory. Cek crontab user tersebut sebelum menyimpulkan apa pun. Direktori di dalam wp-content/uploads, folder cache, atau folder dengan nama acak hampir selalu mencurigakan. Folder uploads seharusnya berisi gambar dan dokumen, bukan file PHP yang mengirim email. Kalau direktori asalnya adalah folder form kontak yang memang sah, bisa jadi file-nya tidak berbahaya tapi disalahgunakan. Misalnya form tanpa CAPTCHA yang dibanjiri bot, atau form yang menerima input header sehingga penerima bisa disisipkan. Perbaikannya di form, bukan dengan menghapus file.
Direktori sudah ketemu, sekarang cari file-nya. Ada dua cara yang saling melengkapi. Pertama, lewat header pesan. Kalau mail.add_x_header aktif di konfigurasi PHP, setiap email dari mail() membawa header X-PHP-Originating-Script yang berisi UID dan nama file skrip. Ambil ID pesan dari log atau dari exim -bp, lalu lihat header-nya. Kedua, lewat waktu modifikasi file. Backdoor biasanya baru ditanam, jadi file PHP yang berubah belakangan ini layak dicek lebih dulu:
BASH
# Lihat header pesan di queue (ganti dengan ID dari log)
exim -Mvh 'ID_PESAN'

# File PHP yang isinya berubah (mtime) atau metadatanya berubah (ctime) dalam 7 hari terakhir
find /home/contohuser/public_html/wp-content/uploads -type f -name '*.php' -mtime -7 -ls
find /home/contohuser/public_html -type f -name '*.php' -ctime -7 -ls
Perintah kedua sengaja memakai -ctime. Penyerang bisa memalsukan mtime dengan touch, tapi ctime ikut berubah setiap kali metadata file diubah dan tidak bisa diatur mundur dengan cara yang sama. Kalau mtime terlihat lama tapi ctime baru, itu tanda file sengaja disamarkan. Setelah nama file ketemu, cari di access log domain tersebut request yang mengarah ke file itu, biasanya berupa POST. Dari situ kelihatan IP penyerang dan kapan file mulai dipanggil. Lokasi access log tergantung panel dan web server, jadi cek di konfigurasi server masing-masing. Request paling awal ke backdoor itu sering jadi petunjuk titik masuk. Cari juga request lain dari IP yang sama di sekitar waktu itu, misalnya upload lewat plugin lama atau login ke panel admin. Jangan langsung menghapus file yang ditemukan. Salin dulu ke lokasi di luar webroot dan catat timestamp-nya. Kalau file dihapus duluan, petunjuk waktu yang dipakai untuk melacak titik masuk ikut hilang.
Ada kalanya log Exim tidak menunjukkan lonjakan apa pun, tapi IP tetap dilaporkan mengirim spam. Penyebab yang sering muncul: skrip membuka koneksi langsung ke port 25 server tujuan tanpa lewat Exim sama sekali. Karena tidak melewati mail server lokal, tidak ada jejak di log Exim. Untuk mengeceknya, lihat koneksi keluar yang sedang aktif ke port 25 dengan ss -tnp state established '( dport = :25 )'. Kolom proses akan menunjukkan PID dan nama proses pemilik koneksi. Kalau yang muncul proses PHP milik user tertentu dan bukan Exim, itu dia. Di WHM ada fitur SMTP Restrictions yang membatasi koneksi SMTP keluar hanya untuk mail server dan root. Cek apakah fitur itu aktif di server kamu, karena tanpa pembatasan semacam ini skrip bisa melewati semua kontrol di Exim.
Menghapus satu file backdoor jarang menyelesaikan masalah. Kalau titik masuknya masih terbuka, file baru biasanya muncul lagi dalam hitungan hari. Urutan yang aman kira-kira seperti ini:
  1. Hentikan pengiriman dulu. Batasi atau tahan email keluar dari akun tersebut supaya reputasi IP tidak makin rusak selama investigasi.
  2. Amankan salinan file mencurigakan, lalu hapus atau karantina dari webroot.
  3. Perbaiki titik masuk: update plugin, tema, dan core CMS, hapus tema atau plugin bajakan, perbaiki form yang bisa disalahgunakan.
  4. Ganti password panel, FTP, database, dan akun admin aplikasi. Kalau ada akun admin yang tidak dikenal, hapus.
  5. Matikan eksekusi PHP di folder uploads supaya file yang lolos upload tidak bisa dijalankan.
  6. Bersihkan sisa spam di queue.
Perhatian untuk langkah terakhir: menghapus pesan dari queue Exim tidak bisa dibatalkan. Pastikan filter yang dipakai hanya mengenai pesan dari akun yang terdampak, misalnya dengan exiqgrep -i -f plus alamat pengirimnya. Cek dulu daftar ID-nya sebelum menjalankan penghapusan, supaya email sah dari akun lain di server yang sama tidak ikut terhapus. Setelah semuanya bersih, pantau lagi hitungan cwd dan ukuran queue selama beberapa hari. Kalau tidak ada lonjakan baru, baru ajukan delisting ke blacklist terkait. Mengajukan delisting sebelum sumbernya benar-benar tertutup biasanya berakhir dengan IP masuk daftar lagi, dan proses keluarnya bisa jadi lebih sulit. Kalau ada satu kebiasaan yang layak dipegang: begitu ada laporan spam dari akun hosting, buka log Exim dan lihat field U=, A=, dan cwd= sebelum menyimpulkan apa pun. Tiga field itu langsung memberi tahu apakah masalahnya password email, skrip di webroot, atau bukan dari server kita sama sekali. Sisanya tinggal mengikuti jejak dari direktori ke file, lalu dari file ke celah yang dipakai untuk menanamnya.