Category: Security

  • How a PostgreSQL Vulnerability Led to a Crypto Mining Malware Infection: An Incident Analysis

    How a PostgreSQL Vulnerability Led to a Crypto Mining Malware Infection: An Incident Analysis

    Date of Incident: May 5, 2025
    Affected System: AlmaLinux 9.5 with cPanel & PostgreSQL

    Incident Summary

    A Linux server running cPanel with PostgreSQL was compromised through a misconfigured PostgreSQL service, which allowed an attacker to upload and execute a malicious binary called cpu_hu. This ELF executable is part of a known crypto mining malware campaign, which abuses PostgreSQL’s permissions to spawn unauthorized processes.


    Indicators of Compromise (IOCs)

    • Suspicious binary: /var/lib/pgsql/data/base/13494/cpu_hu
    • Crontab entries for postgres user triggering binary execution
    • Audit logs showing executions of /usr/bin/s-nail, /usr/sbin/sendmail, and /usr/sbin/exim with UID 26 (PostgreSQL user)
    • Kernel logs in /var/log/messages showing:Killing process <PID> (cpu_hu) with signal SIGKILL
    • PostgreSQL failing to restart due to improper permissions after remediation

    Attack Vector & Execution

    The attacker exploited a misconfigured PostgreSQL installation with either:

    • trust authentication enabled
    • publicly accessible port 5432
    • the ability to execute arbitrary shell commands via SQL extensions like COPY TO PROGRAM

    Once inside, the attacker used the postgres user to:

    1. Upload the ELF binary
    2. Schedule its execution via cron

    Containment & Mitigation Steps

    Step 1: Kill Malware Processes

    pkill -f cpu_hu

    Step 2: Remove Binary

    find / -type f -name '*cpu_hu*' -delete

    Step 3: Clean Up Crontab

    crontab -u postgres -r

    Step 4: Lock Down PostgreSQL

    Edit postgresql.conf and add:

    session_preload_libraries = ''

    Restart service.

    -- Inside psql:
    ALTER USER postgres PASSWORD 'new-strong-password';
    REVOKE EXECUTE ON FUNCTION pg_ls_dir(text) FROM PUBLIC;
    REVOKE EXECUTE ON FUNCTION pg_read_file(text) FROM PUBLIC;
    REVOKE EXECUTE ON FUNCTION pg_stat_file(text) FROM PUBLIC;

    Step 5: Set Correct Permissions

    chown -R postgres:postgres /var/lib/pgsql/data
    chmod 700 /var/lib/pgsql/data
    systemctl restart postgresql

    Step 6: Block Public Access

    iptables -A INPUT -p tcp --dport 5432 -s <trusted_ip> -j ACCEPT
    iptables -A INPUT -p tcp --dport 5432 -j DROP

    Lessons Learned

    • Always restrict PostgreSQL to localhost or VPN access
    • Disable dangerous features like COPY TO PROGRAM unless absolutely required
    • Use auditd rules to track mail/sendmail invocations by non-root users:
    audictl -a always,exit -F arch=b64 -S execve -F uid=26 -F path=/usr/bin/s-nail -k mail_postgres_exec
    • Regularly inspect crontabs and non-root user binaries in /var/lib/ and /tmp

    References


    Status: Resolved