Dampak awal: password sudah diganti, penyusup tetap masuk
wp-login.php hanya satu cara. Ada cookie login yang sudah diterbitkan, ada kredensial terpisah untuk API, ada akun lain di tabel user, dan ada kunci rahasia di wp-config.php yang dipakai untuk menandatangani cookie. Ganti password satu akun tidak menyentuh sebagian besar dari itu.
Jalur investigasi: dari log login ke tabel user
POST /wp-login.php dari IP yang tidak dikenal. Kalau ternyata tidak ada sama sekali tapi perubahan tetap terjadi, berarti penyusup masuk lewat jalur lain.
Tahap kedua, lihat request ke /xmlrpc.php dan /wp-json/. Request ke REST API yang mengubah data, misalnya POST ke endpoint post atau plugin dari IP asing tanpa didahului login, adalah tanda kuat ada kredensial API yang masih hidup. Access log biasanya tidak mencatat header Authorization, jadi kamu hanya melihat polanya, bukan kredensialnya.
Tahap ketiga, bandingkan daftar user di dashboard dengan isi database. Di sinilah temuan paling penting sering muncul. Kode berbahaya bisa memfilter query user sehingga akun tertentu tidak tampil di halaman Users. Karena itu, jangan percaya tampilan dashboard. WP-CLI dengan plugin dan tema dimatikan lebih bisa diandalkan:
BASH
wp user list --role=administrator --skip-plugins --skip-themes --fields=ID,user_login,user_email,user_registeredwp_ dengan $table_prefix di wp-config.php. Meta key-nya juga ikut prefix, misalnya abc_capabilities.
SQL
SELECT u.ID, u.user_login, u.user_email, u.user_registered
FROM wp_users u
JOIN wp_usermeta m ON m.user_id = u.ID
WHERE m.meta_key = 'wp_capabilities'
AND m.meta_value LIKE '%administrator%';Temuan kunci: empat pintu yang tidak ikut terkunci
session_tokens. Validasi cookie melibatkan potongan hash password user. Artinya, saat password akun A diganti, cookie milik akun A ikut tidak berlaku. Tapi cookie akun B, termasuk akun admin tersembunyi tadi, tetap valid sampai kedaluwarsa. Secara default masa berlakunya sekitar dua hari, atau sekitar empat belas hari kalau Remember Me dicentang.
Keempat, salt dan key di wp-config.php. Delapan konstanta seperti AUTH_KEY, LOGGED_IN_KEY, dan pasangan *_SALT dipakai untuk menandatangani cookie. Kalau penyusup pernah bisa membaca file di server, anggap wp-config.php sudah terbaca. Di file yang sama ada kredensial database. Dengan salt plus akses ke hash password di database, cookie yang valid bisa dibuat tanpa pernah login. Dengan kredensial database, akun admin baru bisa disisipkan langsung lewat SQL, apalagi kalau remote MySQL terbuka.
Temuan ini mengubah cara kita melihat insiden. Password admin bukan satu-satunya kunci. Yang bocor bisa jadi seluruh rantai kepercayaan situs.
Mitigasi sementara supaya akses berhenti dulu
- Batasi akses ke
/wp-admin/,wp-login.php, danxmlrpc.phpdi level web server, misalnya allow per IP atau basic auth tambahan. Caranya tergantung Nginx, Apache, LiteSpeed, atau panel yang dipakai. - Matikan Application Passwords sementara dengan mu-plugin kecil berisi
add_filter( 'wp_is_application_passwords_available', '__return_false' );. Ini menutup jalur API berbasis Application Password tanpa menunggu audit per user selesai. - Rotasi salt. Ini cara tercepat untuk membatalkan semua cookie login semua user sekaligus.
Perbaikan yang sebenarnya: urutan mencabut akses
- Bersihkan jalur masuknya dulu. Cari file PHP asing, terutama di
wp-content/mu-plugins/, plugin dan tema yang tidak dikenal, serta file core yang berubah. Update atau hapus plugin yang rentan. Kalau pembersihan tidak meyakinkan, restore dari backup yang jelas bersih. - Audit user dari database. Hapus akun admin yang tidak dikenal, dan pindahkan kontennya ke akun yang sah saat menghapus. Kembalikan role dan email akun lama yang diubah.
- Cabut semua Application Password di setiap akun dengan role tinggi, bukan hanya akun utama.
- Ganti password semua admin, password database (lalu update
DB_PASSWORDdiwp-config.php), serta akses hosting, FTP, dan SSH. Cek juga apakah ada SSH key asing di server. - Rotasi salt paling akhir supaya semua session yang tersisa terputus, termasuk session yang mungkin dibuat selama proses pembersihan.
shuffle-salts menulis ulang wp-config.php dan membuat semua user logout. Backup file itu dulu.
BASH
# lihat Application Password milik user ID 1, termasuk kapan terakhir dipakai
wp user application-password list 1 --skip-plugins --skip-themes
# hapus semua Application Password milik user tersebut
wp user application-password delete 1 --all --skip-plugins --skip-themes
# putus semua session login user tersebut
wp user session destroy 1 --all --skip-plugins --skip-themes
# ganti semua key dan salt di wp-config.php (semua user akan logout)
wp config shuffle-salts