HEX
Server: LiteSpeed
System: Linux sg-cp4.cloudnetwork.vn 4.18.0-553.69.1.lve.el8.x86_64 #1 SMP Wed Aug 13 19:53:59 UTC 2025 x86_64
User: thu28850 (1134)
PHP: 7.4.33
Disabled: NONE
Upload Files
File: //proc/self/root/proc/self/root/opt/imunify360/venv/share/imunify360/scripts/imunify-doctor.sh
#!/bin/bash
VERSION="8.5.8"
LC_ALL=en_US.UTF-8
LANG=en_US.UTF-8
LANGUAGE=en_US.UTF-8
DEST=/root/cl-report
UPLOAD_URL=https://doctor.cloudlinux.com/doctor/upload
CAT=`command -v cat`
UNAME=`command -v uname`
CP="Unknown"
SERVER_ID=
main_ip='NA'
scriptname="imunify-doctor"
IMUNIFY360_PIDFILE=/var/run/imunify360.pid
IMUNIFY360_AGENT_PIDFILE=/var/run/imunify360-agent.pid
# custom tmp dir provisioned by imunify360.spec
tmpdir=/var/imunify360/tmp
sqlite_path=/opt/alt/sqlite/usr/bin/sqlite3
IMUNIFY360_DB=/var/imunify360/imunify360.db
IMUNIFY360_RESIDENT_DB=/var/imunify360/imunify360-resident.db
IMUNIFY360_IPLIST_DB=/var/imunify360/imunify360-ipsetlists.db
db_command="$sqlite_path $IMUNIFY360_DB"
db_command_resident="$sqlite_path $IMUNIFY360_RESIDENT_DB"
db_command_iplist="$sqlite_path $IMUNIFY360_IPLIST_DB"


cleanup() {
  # Set _skip_cleanup=1 before report_error_and_exit so a partially-built
  # report can be kept on disk for offline inspection (e.g. redaction
  # failure path). Defaults to deleting so the success path doesn't leak
  # the blob.
  [ "${_skip_cleanup:-0}" = "1" ] && return 0
  rm -f $DEST $DEST.wget
}

test_curl() {
    command -v curl >/dev/null 2>&1
    return $?
}

test_wget() {
  command -v wget >/dev/null 2>&1
  if [ 0 -eq $? ]; then
    if [ -x `command -v wget` ]; then
	return 0
    fi
  fi
  return 1
}

curl_upload() {
 curl -s -H "serverid: $SERVER_ID" -F reportfile=@"$DEST" $UPLOAD_URL
}

wget_upload() {

    echo -e "--FILEUPLOAD\r\n" > $DEST.wget
    echo -e "--FILEUPLOAD\r\n" > $DEST.wget
    echo -e "Content-Disposition: form-data; name=\"reportfile\"; filename=\"$DEST\"\r\n" >> $DEST.wget
    echo -e "Content-Type: application/octet-stream\r\n" >> $DEST.wget
    echo -e "Media Type: application/octet-stream\r\n\r\n" >> $DEST.wget
    cat $DEST >> $DEST.wget
    echo -e "--FILEUPLOAD--\r\n" >> $DEST.wget
    wget -O - -qq -t 1 --header="serverid: $SERVER_ID" --header="Content-type: multipart/form-data; boundary=FILEUPLOAD" --post-file $DEST.wget $UPLOAD_URL
}

get_server_id() {
  SERVER_ID=$(/opt/imunify360/venv/bin/python -c 'import json; import sys; print(json.load(sys.stdin)["id"])' < /var/imunify360/license.json)
  if [[ -z "$SERVER_ID" ]]; then
    SERVER_ID="${main_ip//./_}"
  fi
  # CWE-93: $SERVER_ID is interpolated into curl/wget `--header` args on
  # upload. Strip everything but the safe alphabet so a poisoned source
  # (license.json or the ${main_ip//./_} fallback whose dots-only filter
  # lets CR/LF through) cannot inject extra HTTP headers.
  SERVER_ID="$(printf '%s' "$SERVER_ID" | LC_ALL=C tr -cd 'A-Za-z0-9._-')"
  if [[ -z "$SERVER_ID" ]]; then
    SERVER_ID="unknown"
  fi
}

init_main_ip() {
 # HTTPS and no `-L` redirect-follow: this value flows into $SERVER_ID when
 # the license-file lookup fails, and then into an HTTP request header on
 # upload — an on-path attacker who controls a plain-HTTP response could
 # inject CRLF and forge headers (CWE-93). Pin to TLS at the source.
 #
 # `curl --max-time 10` is a true total cap. `wget --timeout=10` is
 # per-phase (DNS+connect+TLS+read can each take 10s = up to ~40s wall),
 # so wrap wget in coreutils `timeout` to enforce the same total wall
 # budget the doctor advertises.
 if test_curl
 then
    main_ip=`curl -s --max-time 10 https://cloudlinux.com/showip.php` 2>/dev/null
 else
    main_ip=`timeout 10 wget -qq --timeout=10 --max-redirect=0 -O - https://cloudlinux.com/showip.php` 2>/dev/null
 fi
}

get_main_ip() {
  sep "Main IP"
  echo "$main_ip" >> $DEST
  echo >>$DEST
}


redact_sensitive() {
 # Best-effort scrub of common credential shapes from the collected report
 # before it leaves the host. Runs over $DEST in place. Bypass with
 # `IMUNIFY_DOCTOR_REDACT=0` (e.g. when a Cloudlinux engineer explicitly
 # asks for the raw blob over a trusted channel).
 #
 # On sed failure we DO NOT emit the success footer and we return non-zero,
 # so upload() can refuse to ship a half-scrubbed blob with a misleading
 # "everything was redacted" notice.
 [ "${IMUNIFY_DOCTOR_REDACT:-1}" = "0" ] && return 0
 [ -s "$DEST" ] || return 0

 # Case-insensitive key shapes (matches both JSON keys and shell vars).
 local ci='([Aa][Pp][Ii][_-]?[Kk][Ee][Yy]|[Aa][Pp][Ii][_-]?[Tt][Oo][Kk][Ee][Nn]|[Pp][Aa][Ss][Ss][Ww][Oo][Rr][Dd]|[Pp][Aa][Ss][Ss][Ww][Dd]|[Ss][Ee][Cc][Rr][Ee][Tt]|[Cc][Ll][Ii][Ee][Nn][Tt][_-]?[Ss][Ee][Cc][Rr][Ee][Tt]|[Aa][Ww][Ss][_-]?[Ss][Ee][Cc][Rr][Ee][Tt][_-]?[Aa][Cc][Cc][Ee][Ss][Ss][_-]?[Kk][Ee][Yy]|[Pp][Rr][Ii][Vv][Aa][Tt][Ee][_-]?[Kk][Ee][Yy]|[Bb][Ee][Aa][Rr][Ee][Rr])'
 # Case-sensitive uppercase-only — CSF's actual config-variable name. The
 # csf.conf format is `CLUSTER_KEY = "..."`; the previous `csf_cluster_key`
 # pattern never matched because the real variable has no `csf` prefix.
 local cs='CLUSTER_KEY'
 # Separate patterns for JSON-quoted (terminates at closing `"`) and shell
 # unquoted-or-quoted (terminates at end of line / closing `"`). The
 # previous `[^",[:space:]]+` tail stopped at the first whitespace, so
 # values with spaces (e.g. `DB_PASSWORD=my secret` or `"password":"my secret"`)
 # were only partially scrubbed.
 # Use `#` as the sed delimiter so the `|` alternation in $ci doesn't
 # collide. The captures: \1 = prefix incl. opening quote/`=`, \2 = the
 # matched key name (inner group of $ci/$cs), \3 = closing quote (when
 # present).
 # `[A-Za-z0-9_]*` before $ci allows a common-prefix `DB_PASSWORD`,
 # `MY_API_KEY`, `OAUTH2_CLIENT_SECRET`, `V2_API_KEY` etc. to still match.
 # Digits in the prefix character class matter — `[A-Za-z_]*` would silently
 # skip credential vars whose prefix contains a digit. The trailing value
 # matcher requires a non-quote, non-space starting char so the unquoted
 # rule doesn't backtrack-match a quoted value (the [[:space:]]* before
 # the quote would otherwise be willing to leave the space for [^"]).
 if ! sed -E -i \
      -e "s#(\"[A-Za-z0-9_]*$ci\"[[:space:]]*:[[:space:]]*\")[^\"]*(\")#\1<REDACTED>\3#g" \
      -e "s#(\"[A-Za-z0-9_]*$cs\"[[:space:]]*:[[:space:]]*\")[^\"]*(\")#\1<REDACTED>\2#g" \
      -e "s#(^[[:space:]]*[A-Za-z0-9_]*$ci[[:space:]]*=[[:space:]]*\")[^\"]*(\")#\1<REDACTED>\3#g" \
      -e "s#(^[[:space:]]*[A-Za-z0-9_]*$cs[[:space:]]*=[[:space:]]*\")[^\"]*(\")#\1<REDACTED>\2#g" \
      -e "s#(^[[:space:]]*[A-Za-z0-9_]*$ci[[:space:]]*=[[:space:]]*)[^\"[:space:]].*\$#\1<REDACTED>#g" \
      -e "s#(^[[:space:]]*[A-Za-z0-9_]*$cs[[:space:]]*=[[:space:]]*)[^\"[:space:]].*\$#\1<REDACTED>#g" \
      -e 's#(Authorization:[[:space:]]*Bearer[[:space:]]+)\S+#\1<REDACTED>#gI' \
      "$DEST"; then
   echo "------ REDACTION FAILED ---" >> "$DEST"
   echo "sed -i exited non-zero; the upload will be aborted to avoid shipping" >> "$DEST"
   echo "partially-redacted data alongside a misleading footer. Raw report" >> "$DEST"
   echo "retained at $DEST for offline inspection." >> "$DEST"
   time_stamp
   return 1
 fi

 echo "------ REDACTION ---" >> "$DEST"
 echo "Common credential shapes (api[_-]?key/token, password, secret, client_secret," >> "$DEST"
 echo "aws_secret_access_key, private_key, bearer, CLUSTER_KEY, Authorization:" >> "$DEST"
 echo "Bearer ...) were replaced with <REDACTED>. Set IMUNIFY_DOCTOR_REDACT=0 to" >> "$DEST"
 echo "disable when sending a raw blob over a trusted channel." >> "$DEST"
 time_stamp
 return 0
}

upload() {
 if ! redact_sensitive; then
     # Suspend cleanup so the operator can inspect $DEST (the failure
     # footer in redact_sensitive points at this file).
     _skip_cleanup=1
     report_error_and_exit "redaction failed; refusing to upload. Raw report retained at $DEST."
 fi
 if test_curl
 then
     curl_upload
 else
     wget_upload
 fi
}

report_error_and_exit() {
 echo "$1"
 exit 1
}

mecho(){
 echo $1 >> $DEST
}
start(){
 if ! test_wget; then
     if ! test_curl; then
	 echo "Cannot find wget or curl"
     fi
     #echo "Using curl"
 fi
 echo "------ CL INFO ---" > $DEST
}

time_stamp(){
 echo "" >> $DEST
 echo "TS: $(date)" >> $DEST
}

sep(){
 echo "------ $1 ---" >> $DEST
}


run(){
 sep "$1"
 sh -c "$1" >> $DEST 2>&1
 time_stamp
}

run_cb(){
 sep "$1"
 $1 >> $DEST 2>&1
 result=$?
 time_stamp
 return $result
}

dump() {
 sep "cat $1"
 $CAT $1  >> $DEST 2>&1
 echo >> $DEST 2>&1
 time_stamp
}


detect_cp() {
    CP_VERSION="Unknown"
    SOFTACULOUS=0
    if [ -d "/usr/local/psa/admin/" ]; then
	    CP="Plesk"
        CP_VERSION=`cat /usr/local/psa/version`
	    if [ -e "/usr/local/softaculous" ]; then SOFTACULOUS=1; fi
    fi
    if [ -d "/usr/local/cpanel/whostmgr/docroot/" ]; then
	    CP="cPanel"
        CP_VERSION=`/usr/local/cpanel/cpanel -V`
	    if [ -e "/usr/local/cpanel/whostmgr/cgi/softaculous" ]; then SOFTACULOUS=1; fi
    fi
    if [ -d "/usr/local/interworx/" ]; then
	    CP="InterWorx"
        CP_VERSION=`cat /usr/local/interworx/iworx.ini|grep version`
	    if [ -e "/usr/local/softaculous" ]; then SOFTACULOUS=1; fi
    fi
    if [ -d "/usr/local/ispmgr/" ]; then
	    CP="ISPmanager"
        CP_VERSION=`/usr/local/ispmgr/bin/ispmgr -v`
	    if [ -e "/usr/local/softaculous" ]; then SOFTACULOUS=1; fi
    fi
    if [ -d "/usr/local/directadmin/plugins/" ]; then
	    CP="DirectAdmin"
        CP_VERSION=`/usr/local/directadmin/custombuild/build versions|sed -n 2p|cut -d":" -f2`
	    if [ -e "/usr/local/directadmin/plugins/softaculous" ]; then SOFTACULOUS=1; fi
    fi
    if [ -d "/usr/local/hostingcontroller/" ]; then
	    CP="Hosting Controller"
	    if [ -e "/usr/local/softaculous" ]; then SOFTACULOUS=1; fi
    fi
    if [ -d "/hsphere/shared" ]; then
        CP="H-Sphere"
    fi
    sep "Control Panel"
    mecho "CP: $CP"
    mecho "VERSION: $CP_VERSION"
    mecho "SOFTACULOUS: $SOFTACULOUS"
}

detect_httpd() {

    PERL_BIN=$(which perl 2>>/dev/null)

    echo
    echo "HTTP Server Running Processes: "
    echo

    # Filter to euid==0 only — same threat model as the http_bins block
    # below (DEF-38151): an unprivileged local user can `exec -a httpd`
    # any binary they like, which would have caused us to dump their
    # /proc/<pid>/environ into a report later uploaded to the cloud.
    IFS=$(echo -en "\n\b")
    for proc in $(ps -eo euid,pid,user,group,cmd 2>>/dev/null | awk '$1 == 0 {$1=""; sub(/^ +/,""); print}' | egrep "\b(httpd|apache2|litespeed|lshttpd)\b" | grep -v "egrep"); do
        echo "[$proc]"
        proc_pid=$(echo "$proc" | awk '{print$1}')
        echo "Bin:" $(readlink "/proc/${proc_pid}/exe" 2>>/dev/null)
        echo "Environment:"
        cat "/proc/${proc_pid}/environ"  2>>/dev/null | tr '\0' '\n' | head -30
        echo
    done
    unset IFS
    echo

    # Only consider httpd/apache2 processes running as root (euid 0) to
    # prevent local privilege escalation via attacker-controlled binaries
    # that match the "httpd"/"apache2" process name (DEF-38151).
    http_bins=$(ps -eo euid,pid,comm 2>>/dev/null | awk '$1 == 0' | egrep "\b(httpd|apache2)\b" | awk '{print "/proc/"$2"/exe"}' | xargs -n 1 readlink 2>/dev/null | sort -u | egrep "\b(httpd|apache2)\b")

    for http_bin in $http_bins; do

        if [ -z "$http_bin" ]; then
            continue
        fi

        echo "HTTP Binary Info: "
        echo -e "$http_bin\n"
        $http_bin -V 2>&1
        echo
        $http_bin -M 2>&1
        echo

        if [ -z "$PERL_BIN" ]; then
            continue
        fi

        httpd_root=$($http_bin -V | grep HTTPD_ROOT | cut -d= -f2 | tr -d '"' )
        httpd_config=$($http_bin -V | grep SERVER_CONFIG_FILE | cut -d= -f2 | tr -d '"' )

        if [ -z "$httpd_config" ]; then
            continue
        fi

        if [ ! ${httpd_config:0:1} = "/" ]; then
            httpd_config="$httpd_root/$httpd_config"
        fi

        pl_script_path="$(dirname $(readlink -e "$0"))/mk_apache_conf_digest.pl"
        if [ -e "$pl_script_path" ]; then
            echo "Server Configs:"
            $PERL_BIN "$pl_script_path" "$httpd_config" "$httpd_root" 2>>/dev/null
        fi

    done

}


http_server_info() {
    detect_httpd 2>>/dev/null | head -5000
}


backup_systems_info() {
    if [ ! -f /var/restore_infected/acronis_api_token.json ]; then
        echo "/var/restore_infected/acronis_api_token.json: no such file."
    else
        echo "/var/restore_infected/acronis_api_token.json: "
        # "username": "AB-99658-51"
        /opt/imunify360/venv/bin/python -m json.tool < /var/restore_infected/acronis_api_token.json
    fi

    echo
    echo "imunify360-agent backup-systems extended-status: "
    mkdir -p -m 0700 "$tmpdir" 2>/dev/null
    local _bsi
    _bsi="$(mktemp -p "$tmpdir" backup_systems_info.XXXXXX)" || return 1
    if [ -L "$_bsi" ] || [ ! -O "$_bsi" ] || [ ! -f "$_bsi" ]; then
        rm -f "$_bsi"
        return 1
    fi
    imunify360-agent backup-systems extended-status -v --json | tee "$_bsi"
    /opt/imunify360/venv/bin/python <<ENDPY
import json
print(json.load(open("$_bsi"))["items"]["backup_system"])
ENDPY

    rm -f "$_bsi"
}


webshield_selfcheck() {
    /usr/share/imunify360-webshield/self_check.py
}


pam_db_size() {
    mod_db_path=$(awk -F= '$1 == "mod_db_path" {print $2}' /etc/pam_imunify/i360.ini)
    du --human-readable --summarize "$mod_db_path"
}

version() {
    sep "Version of doctor script"
    echo "Version: $VERSION" >> $DEST
}

trap cleanup EXIT

start
version
init_main_ip
get_main_ip
get_server_id
detect_cp
run "date"
run "$CAT /proc/cpuinfo"
run "$UNAME -a"
run "$UNAME -r"
run "$UNAME -m"
run "$UNAME -p"
run "$UNAME -o"
dump "/etc/redhat-release"
dump "/etc/os-release"
dump "/var/imunify360/license.json"
dump "/etc/sysconfig/imunify360/imunify360.config"
dump "/etc/sysconfig/imunify360/imunify360-merged.config"
run "tail -n +1 /etc/sysconfig/imunify360/imunify360.config.d/*"
dump "/etc/sysconfig/imunify360/cpanel/imunify360.conf"
run "ls -lhaR /var/lib/unified-access-logger"
run "du -hs0 /var/lib/unified-access-logger"
run "tail -n3000 /var/log/imunify360/console.log"
run "tail -n3000 /var/log/imunify360/debug.log"
run "tail -n3000 /var/log/imunify360/network.log"
run "tail -n3000 /var/log/imunify360/acronis-installer.log"
run "tail -n3000 /var/log/imunify360/error.log"
run "tail -n3000 /var/log/imunify360/imunify-agent-proxy.log"
run "tail -n3000 /var/log/imunify360-webshield/access.log"
run "tail -n3000 /var/log/imunify360-webshield/error.log"
run "tail -n3000 /var/ossec/logs/alerts/alerts.log"
run "tail -n3000 /usr/local/directadmin/custombuild/custombuild.log"
run "tail -n3000 /var/log/patchman/patchman.log"
dump "/etc/issue"
dump "/etc/sysconfig/kernel"
dump "/etc/sysconfig/kcare/systemid"
dump "/proc/uptime"
dump "/proc/loadavg"
dump "/proc/vmstat"
dump "/proc/devices"
dump "/proc/diskstats"
dump "/proc/cmdline"
dump "/proc/mdstat"
dump "/proc/meminfo"
dump "/proc/swaps"
dump "/proc/filesystems"
dump "/proc/mounts"
dump "/proc/interrupts"
dump "/boot/grub/grub.conf"
dump "/proc/version"
dump "/etc/passwd"

run "ls -la /etc/apt/sources.list.d/"
run "tail -n 50 /etc/apt/sources.list.d/*imunify*"
run "ls -la /etc/apt/preferences.d/"
run "tail -n 50 /etc/apt/preferences.d/*"

run "zgrep -C 5 imunify /var/log/apt/history.log*"
run "zgrep -C 5 imunify /var/log/apt/term.log*"
run "apt policy imunify360-firewall"

run "ls -la /etc/yum.repos.d/"
run "tail -n 50 /etc/yum.repos.d/{*imunify360*,*sensor*}"
run "grep DEFAULT /etc/default/grub"
run "grep vmlinuz /boot/grub2/grub.cfg| sed 's/root=.*//'"
dump "/boot/grub2/grub.cfg"
dump "/proc/zoneinfo"
run "ls /etc/grub.conf /boot/grub/grub.conf /boot/grub/menu.lst"
run "ls -l /boot"
run "grep Port /etc/ssh/sshd_config"
run "dmidecode"
run "systemd-detect-virt"
run "virt-what"
run "ipcs -m|sed -e s/-/=/g"
run "sysctl -a"
dump "/etc/sysctl.conf"
run 'rpm -q -a --queryformat="%{N}|%{V}-%{R}|%{arch}\n"'
# Package integrity check — prefer a freshly-downloaded copy whose detached
# signature verifies against the CloudLinux GPG pubkey already installed by
# imunify-release; fall back to the copy shipped in imunify-core on any
# error. Only a verified copy is allowed to execute.
_integrity_local=""
for _p in /opt/imunify360/venv/share/imunify360/scripts/imunify-check-pkg-integrity \
          /usr/share/imunify360/scripts/imunify-check-pkg-integrity; do
    [ -x "$_p" ] && { _integrity_local="$_p"; break; }
done

_integrity_remote=""
_integrity_workdir=""
_integrity_url="https://repo.imunify360.cloudlinux.com/defence360/imunify-check-pkg-integrity.sh"

_integrity_pubkey=""
for _k in /etc/pki/rpm-gpg/RPM-GPG-KEY-CloudLinux-Imunify \
          /etc/apt/trusted.gpg.d/RPM-GPG-KEY-CloudLinux.gpg; do
    [ -r "$_k" ] && { _integrity_pubkey="$_k"; break; }
done

if [ -n "$_integrity_pubkey" ] && command -v gpg >/dev/null 2>&1; then
    mkdir -p -m 0700 "$tmpdir" 2>/dev/null
    _integrity_workdir="$(mktemp -d -p "$tmpdir" imunify-check-pkg-integrity.XXXXXX 2>/dev/null)"
    if [ -n "$_integrity_workdir" ] && [ -d "$_integrity_workdir" ] \
       && [ ! -L "$_integrity_workdir" ] && [ -O "$_integrity_workdir" ]; then
        _dl_script="$_integrity_workdir/imunify-check-pkg-integrity.sh"
        _dl_sig="$_integrity_workdir/imunify-check-pkg-integrity.sh.sig"
        _gpg_home="$_integrity_workdir/gnupg"
        mkdir -m 0700 "$_gpg_home"
        _ok=1
        if test_curl; then
            curl -sf -o "$_dl_script" "$_integrity_url"     2>/dev/null && \
            curl -sf -o "$_dl_sig"    "${_integrity_url}.sig" 2>/dev/null || _ok=0
        elif test_wget; then
            wget -q -O "$_dl_script" "$_integrity_url"     2>/dev/null && \
            wget -q -O "$_dl_sig"    "${_integrity_url}.sig" 2>/dev/null || _ok=0
        else
            _ok=0
        fi
        # gpg --import handles both ASCII-armored and binary pubkey files.
        if [ $_ok -eq 1 ] \
            && GNUPGHOME="$_gpg_home" gpg --batch --quiet --import "$_integrity_pubkey" 2>/dev/null \
            && GNUPGHOME="$_gpg_home" gpg --batch --quiet --verify "$_dl_sig" "$_dl_script" 2>/dev/null; then
            chmod +x "$_dl_script"
            _integrity_remote="$_dl_script"
        fi
    fi
fi

if [ -n "$_integrity_remote" ]; then
    run "$_integrity_remote"
elif [ -n "$_integrity_local" ]; then
    run "$_integrity_local"
else
    sep "imunify-check-pkg-integrity"
    echo "SKIPPED: signed remote copy unavailable and imunify-check-pkg-integrity not installed locally." >> $DEST
    echo "Install/repair the imunify-core package to enable this check." >> $DEST
    time_stamp
fi

[ -n "$_integrity_workdir" ] && rm -rf "$_integrity_workdir"

run "dpkg -l"
run "tail -n10000 /var/log/messages"
run "ls -lR /var/cache/kcare/"
dump "/etc/sysconfig/kcare/kcare.conf"
dump "/etc/kdump.conf"
run "/opt/imunify360/venv/bin/python -m pip freeze"
# Read the pidfile into a numeric-only var FIRST (no `sh -c "$(cat ...)"`
# expansion at run time — the previous form was a TOCTOU/symlink hazard:
# the pidfile is read inside the `sh -c` body, after the [[ -f ]] check,
# so a swap between check and use would inject shell bytes. Sanitize to
# digits before re-using.
_dump_pidfile_fds() {
  local pidfile="$1"
  [[ -f "$pidfile" ]] || return
  local pid
  pid="$(tr -cd '0-9' < "$pidfile")"
  [[ -n "$pid" && -d "/proc/$pid" ]] || return
  sep "$pidfile"
  echo "$pidfile" >> "$DEST"
  ls -l "/proc/$pid/fd" >> "$DEST" 2>&1
  time_stamp
}
_dump_pidfile_fds "$IMUNIFY360_PIDFILE"
_dump_pidfile_fds "$IMUNIFY360_AGENT_PIDFILE"


run "df -h"
dump "/etc/userdomains"

run "ps aux --sort=-%mem | head -20"
run "ps aux --sort=-%cpu | head -20"
run "ps aux | grep -i imunify"

run "crontab -l"
run "service imunify360 status"
run "service imunify-antivirus status"
run "service imunify360-webshield status"
run "service wsshdict status"
run "service firewalld status"
run "service ossec-hids status"
run "service fail2ban status"
run "service httpd status"
run "service lshttpd status"
run "service patchman-client status"

run_cb "webshield_selfcheck"

run_cb "pam_db_size"
run "imunify360-pam status --yaml"
run "ls -la /etc/pam.d/"
run "cat /etc/pam_imunify/i360.ini"

if [ -e "/usr/sbin/csf" ]; then
  run "csf --status"
  run "lfd --status ; echo $?"
  run "service lfd status"
  run "service csf status"
  run "csf -V"
  dump "/etc/csf/csf.conf"
  dump "/etc/csf/csf.deny"
  dump "/etc/csf/csf.allow"
  dump "/etc/csf/csf.ignore"
  run "tail -n3000 /var/log/lfd.log"
fi
run "cxs --version"

if [ -e "/usr/bin/firewall-cmd" ]; then
    run "timeout 5 firewall-cmd -V"
    run "timeout 5 firewall-cmd --state"
    run "tail -n3000 /var/log/firewalld"
fi

run "service cpanel status"
dump "/var/cpanel/dnsonly"
run "service mysql status"
run "ps aux | grep -i cphulk"

run "ipset -V"
run "ipset save | head -n3000"
run "ipset list -t | head -n3000"
run "iptables -V"
run "iptables-save | head -n3000"
dump "/proc/sys/net/ipv6/conf/all/disable_ipv6"

run "ifconfig"
run "echo .tables | $db_command"
run "echo \"select plugin, count(*) from incident;\" | $db_command_resident"
run "echo \"select listname, count(*) from iplist;\" | $db_command_resident"
run "echo \"select iplist_id, count(*) from iplistrecord;\" | $db_command_iplist"
run "echo \"select * from iplist order by ctime desc limit 1000;\" | $db_command_resident"
run "echo \"select * from incident order by timestamp desc limit 1000;\" | $db_command_resident"
run "echo \"select * from country limit 1000;\" | $db_command"
run "echo \"select * from country_list order by ctime desc limit 1000;\" | $db_command"
run "echo \"select * from last_synclist limit 1000;\" | $db_command_resident"
run "echo \"select * from migratehistory limit 1000;\" | $db_command"
run "echo \"select * from malware_hits limit 1000;\" | $db_command"
run "echo \"select * from malware_ignore_path limit 1000;\" | $db_command"
run "echo \"select * from malware_scans limit 1000;\" | $db_command"
run "du --human-readable /var/imunify360/imunify360.db"
run "imunify360-agent blacklist country list --json --limit 2000"
run "imunify360-agent ip-list local list --purpose drop --limit 2000"
run "imunify360-agent graylist ip list --json --limit 2000"
run "imunify360-agent whitelist country list --json --limit 2000"
run "imunify360-agent ip-list local list --purpose white --limit 2000"
run "imunify360-agent blocked-port list"

run "imunify360-agent rstatus"
run "imunify360-agent rstatus --json -v"
run "imunify360-agent version"
run "imunify360-agent 3rdparty conflicts --json | /opt/imunify360/venv/bin/python -m json.tool"
run "imunify360-agent config show --json -v"
run "imunify360-agent notifications-config show --json -v"
run "grep License /var/log/imunify360/console.log | tail -n 1000"
run "grep 'Server is offline' /var/log/imunify360/console.log | tail -n 1000"
run "grep 'SensorAlert' /var/log/imunify360/console.log | tail -n 3000"
run "grep 'modsec' /var/log/imunify360/console.log | tail -n 3000"
run "ls -la /etc/sysconfig/imunify360/"
run_cb "backup_systems_info"

run "tail -n3000 /var/log/i360deploy.log"
run "tail -n3000 /var/log/imav-deploy.log"
run "tail -n3000 /var/ossec/logs/active-responses.log"
run "tail -n3000 /var/ossec/logs/alerts/alerts.log"
run "tail -n3000 /var/log/yum.log"
run "tail -n3000 /var/log/minidaemon.log"

# cPanel
run "tail -3000 /usr/local/apache/logs/error_log"
run "tail -3000 /usr/local/apache/logs/access_log"
run "tail -3000 /usr/local/apache/logs/modsec_audit.log"
# EA4
run "tail -3000 /etc/apache2/logs/modsec_audit.log"
# plesk
run "tail -3000 /usr/local/apache/logs/modsec_audit.log"
# DA
run "tail -3000 /var/log/httpd/modsec_audit.log"

run "tail -3000 /var/log/trueimage-setup.log"

run "/usr/local/cpanel/scripts/modsec_vendor list"
run "whmapi1 modsec_get_configs"
run "whmapi1 modsec_get_settings"
run "cat /etc/apache2/conf.d/modsec2.imunify.conf"
run "cat /usr/local/apache/conf/includes/modsec2.imunify.conf"
run "ls /var/cpanel/cwaf"

# prepend each particular log with ==> logfilename <== string
run "tail --lines +0 /var/log/imunify360/register_unregister_post_error_*.log"

# prepend each particular log with ==> logfilename <== string
run "tail --lines +0 /var/log/imunify360/*hardenedphp.log.*"
run "tail --lines +0 /var/log/imunify360/*kernelcare.log*"
run "tail --lines +0 /var/log/imunify360/*ea_php.log*"
run "ls /opt/alt/php*/usr/bin/php"
run "ls /opt/cpanel/ea-php*/root/usr/bin/php"
run 'rpm -qa --queryformat "%{NAME} %{RELEASE}\n" "ea-php*"'

run "getenforce"
run "sestatus"
run "ss -u -a"
run "ss -x -a | grep defence360agent"
run "timeout 10 nc -v -w 5 -i 1 imunify360.cloudlinux.com 443"
run "timeout 10 nc -v -w 5 -i 1 148.251.142.83 443"
dump "/usr/local/cpanel/version"
run "ls /etc/rc.d/init.d/"
run "systemctl list-units --all"
run "systemctl status aibolit-resident.socket"
run "curl ipinfo.io"
run "netstat -tulpan | tail -n 3000"
run "netstat -tulpan | wc -l"
# only tcp listening sockets & program
run "netstat -tlpn"
run "lsmod | grep ip_set"
dump "/etc/cagefs/cagefs.mp"
for f in /var/log/imunify360/native_da.hook_log.*
do dump $f
done

### PLESK
run "/usr/local/psa/admin/sbin/modsecurity_ctl --list-rules"
run "/usr/local/psa/admin/sbin/modsecurity_ctl --list-rules --enabled"
run "/usr/local/psa/admin/sbin/modsecurity_ctl --status"
run "/usr/local/psa/bin/server_pref --show-web-app-firewall"

run_cb "http_server_info"
# collect info on how huge /var/cpanel/secdatadir/ip.pag is
run "ls -lh /var/cpanel/secdatadir/*"
run "printenv"

run "/usr/libexec/run-with-intensity show"

# colect webshield  info
run "tail -3000 /var/log/wsshdict/wsshdict.log"
run "tail -3000 /var/log/imunify360/imunify360-wafd.log"

# collect UAL log
run "tail -3000 /var/log/imunify360/imunify360-unified-access-logger/log.rotate"

if [ -e "/etc/kdump.conf" ]; then
  KDUMP_PATH=`grep ^path /etc/kdump.conf|cut -d' ' -f2`
  if [ -z "$KDUMP_PATH" ] ; then
    run "ls -lR /var/crash"
  else
    run "ls -lR $KDUMP_PATH"
  fi
fi
run dmesg

run "ls -la /var/ossec/etc/VERSIONS/"
run "ls --lcontext /var/ossec"
run "ls --lcontext /var/ossec/bin"
run "ls --lcontext /var/ossec/logs"

run "ls -la /etc/httpd/conf/modsecurity.d/rules/"
run "ls -la /etc/apache2/conf.d/modsec_vendor_configs/"

run "cat /etc/httpd/conf/modsecurity.d/rules/custom/VERSION"
run "cat /usr/local/directadmin/custombuild/custom/modsecurity/conf/VERSION"
run "cat /etc/apache2/conf.d/modsec_vendor_configs/imunify*/VERSION;echo"
run "cat /var/cpanel/modsec_cpanel_conf_datastore"

run "cut -d\":\" -f1 /etc/userplans | sort -n | uniq | wc -l"
run "cut -d\":\" -f1 /etc/userplans | sort -n | uniq"
run "cut -d\":\" -f2 /etc/virtual/domainowners | sort -n | uniq"
run "cut -d\":\" -f2 /etc/virtual/domainowners | sort -n | uniq | wc -l"
run "plesk db \"SELECT COUNT(DISTINCT cl_id) FROM domains\""
run "httpd  -t"

run "journalctl --no-pager -u imunify360 --since -1d"
run "journalctl --no-pager -u imunify360-agent --since -1d"
run "journalctl --no-pager -u imunify360-unified-access-logger --since -1d"

# Imunify Email
run "ie-config status"

upload && echo || report_error_and_exit "Report file upload failed. Please try again."