Commit e01648b2 authored by 易初's avatar 易初 🖐🏻

Add new file

parents
#!/bin/bash
# server_incident_scan_v3.sh
# Read-only, cross-host incident triage for the 2026-09-11 intrusion.
# Compatible with the older Bash/procps/findutils commonly found on CentOS 6/7.
#
# No processes are stopped, no packages are changed, no accounts/keys are
# modified, and no firewall/service/repository configuration is changed.
# The script only writes its evidence directory. Reading files may update atime
# on filesystems mounted with strict atime semantics.
set -u
umask 077
export LC_ALL=C
VERSION="3.0.0"
SCAN_START="${SCAN_START:-2026-09-11 00:00:00}"
SCAN_END="${SCAN_END:-2026-09-12 06:00:00}"
BASE_OUT="/var/tmp"
MODE="standard"
usage() {
cat <<'EOF'
Usage:
server_incident_scan_v3.sh [--output DIR] [--start DATETIME] [--end DATETIME] [--deep]
Options:
--output DIR Evidence parent directory (default: /var/tmp)
--start DATETIME Incident window start (default: 2026-09-11 00:00:00)
--end DATETIME Incident window end (default: 2026-09-12 06:00:00)
--deep Add broader recent-file inspection under system paths
-h, --help Show this help
Backward compatibility:
A single positional directory is accepted as the output parent.
Examples:
bash server_incident_scan_v3.sh --output /root
bash server_incident_scan_v3.sh --output /root --deep
EOF
}
while test "$#" -gt 0; do
case "$1" in
--output)
test "$#" -ge 2 || { usage >&2; exit 1; }
BASE_OUT="$2"; shift 2 ;;
--start)
test "$#" -ge 2 || { usage >&2; exit 1; }
SCAN_START="$2"; shift 2 ;;
--end)
test "$#" -ge 2 || { usage >&2; exit 1; }
SCAN_END="$2"; shift 2 ;;
--deep)
MODE="deep"; shift ;;
-h|--help)
usage; exit 0 ;;
--*)
echo "Unknown option: $1" >&2; usage >&2; exit 1 ;;
*)
BASE_OUT="$1"; shift ;;
esac
done
have() {
command -v "$1" >/dev/null 2>&1
}
HOST_NAME="$(hostname 2>/dev/null || echo unknown-host)"
SAFE_HOST="$(printf '%s' "$HOST_NAME" | tr -c 'A-Za-z0-9._-' '_')"
STAMP="$(date +%Y%m%d-%H%M%S)"
OUT_DIR="${BASE_OUT%/}/incident-scan-v3-${SAFE_HOST}-${STAMP}"
ARTIFACTS="$OUT_DIR/artifacts"
RAW="$OUT_DIR/evidence.txt"
FINDINGS="$OUT_DIR/findings.tsv"
SUMMARY="$OUT_DIR/summary.txt"
EVENTS="$OUT_DIR/chain_events.tsv"
PROCESSES="$OUT_DIR/processes.tsv"
CONNECTIONS="$OUT_DIR/public_remote_connections.tsv"
SSH_SUCCESS="$OUT_DIR/ssh_success.log"
FILES="$OUT_DIR/recent_files.tsv"
SCRIPTS="$OUT_DIR/cloud_assist_scripts.tsv"
ENDPOINTS="$OUT_DIR/candidate_endpoints.txt"
mkdir -p "$ARTIFACTS/processes" "$ARTIFACTS/cloud-assist-scripts" \
"$ARTIFACTS/authorized-keys" "$ARTIFACTS/package-metadata" \
"$ARTIFACTS/campaign-files" "$ARTIFACTS/binary-indicators" || exit 1
: > "$RAW"
: > "$SSH_SUCCESS"
printf 'host\tseverity\tstage\tcategory\tevidence\n' > "$FINDINGS"
printf 'host\ttime\tstage\tsource\tindicator\tevidence\n' > "$EVENTS"
printf 'host\tpid\tppid\tuser\tstart\tcomm\texe\tsha256\tcmdline\n' > "$PROCESSES"
printf 'host\tprotocol\tlocal_address\tremote_address\tstate\tpid_program\n' > "$CONNECTIONS"
printf 'host\ttime_type\ttime\tmode\tuid_gid\tsize\tsha256\tpath\n' > "$FILES"
printf 'host\tmtime\tsha256\tpath\tclassification\n' > "$SCRIPTS"
: > "$ENDPOINTS"
# Confirmed campaign indicators.
BAD_KEY_SHA256='SHA256:/6Ll/VlsnRWorwg3IpUSNSosKJxNNA6znrR+QTXQRaE'
CURSOR_KEY_FRAGMENT='AAAAB3NzaC1yc2EAAAADAQABAAABAQCF8tdOgKz0byyI/1wsvYH7/dAH71F7QDr4W7PQu8aCH8'
PIVOT_KEY_FRAGMENT='AAAAB3NzaC1yc2EAAAADAQABAAABAQC4evWpxa5XJ8KiL1+E32x1MB7FlijaDTHVhBOwL7xhr0GvZGLj'
KNOWN_AK_ID='LTAI4FjyvUTRZZN4QyHoXQag'
IOC_TEXT_REGEX='101\.201\.148\.142|8\.217\.173\.211|hdocf\.com|ddocf\.com|watch_dog_auth|hpgoc2([.-]|\.oss\.v2\.core)|cursor-agent-010|aliyun-sys-assist|AliyunSysAssist|/tmp/dbg([^A-Za-z0-9_.-]|$)|libnuma_hint\.so|url_key=hpgoc2|LTAI4FjyvUTRZZN4QyHoXQag'
IOC_EXEC_REGEX='AuthorizedKeysCommand|authorized_keys|unset[[:space:]]+HISTFILE|rpm[[:space:]]+-Uvh|/tmp/sys\.rpm|/tmp/elf\.rpm|/tmp/kd\.rpm|dbg-el6|aliyun-sys-assist'
sanitize() {
local _value
_value="$1"
printf '%s' "$_value" | tr '\t\r\n' ' '
}
section() {
local _title
_title="$1"
printf '\n===== %s =====\n' "$_title" >> "$RAW"
}
finding() {
local _sev _stage _category _evidence _line
_sev="$1"
_stage="$2"
_category="$3"
_evidence="$(sanitize "$4")"
_line="$(printf '%s\t%s\t%s\t%s\t%s' "$HOST_NAME" "$_sev" "$_stage" "$_category" "$_evidence")"
if ! grep -Fqx -- "$_line" "$FINDINGS" 2>/dev/null; then
printf '%s\n' "$_line" >> "$FINDINGS"
fi
}
event() {
local _time _stage _source _indicator _evidence
_time="$(sanitize "$1")"
_stage="$(sanitize "$2")"
_source="$(sanitize "$3")"
_indicator="$(sanitize "$4")"
_evidence="$(sanitize "$5")"
printf '%s\t%s\t%s\t%s\t%s\t%s\n' \
"$HOST_NAME" "$_time" "$_stage" "$_source" "$_indicator" "$_evidence" >> "$EVENTS"
}
hash_value() {
local _target
_target="$1"
if have sha256sum; then
sha256sum "$_target" 2>/dev/null | awk '{print $1}'
elif have shasum; then
shasum -a 256 "$_target" 2>/dev/null | awk '{print $1}'
elif have openssl; then
openssl dgst -sha256 "$_target" 2>/dev/null | awk '{print $NF}'
fi
}
hash_label() {
local _digest
_digest="$1"
case "$_digest" in
aa0eb857cbb40a1516ba0f6ac33d2265d0b49e9067abeec4264057193e440e09)
echo "dbg payload" ;;
87f629925728922e2b092036b214b364b2419452a514d0b44f033ebe4a0d873c)
echo "malicious irqbalance variant 1" ;;
a3d832da2bd83bff45fb1df576de814f57b004777ea0dd7d1beaa46340d8ca49)
echo "malicious irqbalance variant 2" ;;
ca90137ec7f88f9426e2a0b591d125b6ee20f75b30e4fd9445cdbbf402594a57)
echo "malicious libnuma_hint.so" ;;
8ca077298ca5a46655be209bd993268e5e224f0bc10a079825e023e036d342fe)
echo "malicious AliyunSysAssist" ;;
f5403e362abf1ac6a4d3628f305110c6f1aa8d1ddea0922b3757ba3281ff7bc3)
echo "malicious aliyun-sys-assist core.so" ;;
b174e5a7debf48004811e58be69cfaad607af379c3dcbf268772f84be88a2b8f)
echo "malicious aliyun-sys-assist setup" ;;
17a45ace32f6343b35c3300658e1ebdd3865608c6b20d2e3c0e13344b3b73a68)
echo "malicious aliyun-sys-assist configuration" ;;
*)
echo "" ;;
esac
}
classify_hash() {
local _digest _path _label
_digest="$1"
_path="$2"
_label="$(hash_label "$_digest")"
if test -n "$_label"; then
finding CRITICAL execution hash "Known campaign hash $_digest ($_label) at $_path"
event "$(date '+%F %T %z')" execution filesystem "$_label" "$_path sha256=$_digest"
fi
}
copy_artifact() {
local _source _destination
_source="$1"
_destination="$2"
test -r "$_source" || return 0
cp -p "$_source" "$_destination" >> "$RAW" 2>&1 || true
chmod go-rwx "$_destination" 2>/dev/null || true
}
file_evidence() {
local _path _reason _digest _label _safe_name
_path="$1"
_reason="$2"
test -e "$_path" || test -L "$_path" || return 0
echo "-- $_path ($_reason) --" >> "$RAW"
stat "$_path" >> "$RAW" 2>&1
file "$_path" >> "$RAW" 2>&1
_digest=""
if test -f "$_path" && test -r "$_path"; then
_digest="$(hash_value "$_path")"
echo "sha256=$_digest" >> "$RAW"
classify_hash "$_digest" "$_path"
_label="$(hash_label "$_digest")"
if test -n "$_label" \
|| test "$_path" = /usr/sbin/aliyun-sys-assist-setup \
|| printf '%s' "$_path" | grep -q '^/usr/local/share/aliyun-sys-assist/' \
|| printf '%s' "$_path" | grep -q '^/usr/lib/aliyun-sys-assist-payload/' \
|| { test "$_path" = /usr/sbin/irqbalance && test "${IRQ_RPM_BAD:-0}" -eq 1; }; then
_safe_name="$(basename "$_path" | tr -c 'A-Za-z0-9._-' '_')"
copy_artifact "$_path" "$ARTIFACTS/campaign-files/${_digest}-${_safe_name}"
fi
if test "$_path" = /usr/sbin/irqbalance && test "${IRQ_RPM_BAD:-0}" -eq 1; then
finding CRITICAL execution hash "Altered /usr/sbin/irqbalance sha256=$_digest (known or newly observed variant)"
fi
fi
if have rpm; then rpm -qf "$_path" >> "$RAW" 2>&1; fi
}
START_EPOCH="$(date -d "$SCAN_START" +%s 2>/dev/null || echo 0)"
END_EPOCH="$(date -d "$SCAN_END" +%s 2>/dev/null || echo 0)"
if test "$START_EPOCH" -eq 0 || test "$END_EPOCH" -eq 0 || test "$START_EPOCH" -ge "$END_EPOCH"; then
echo "Invalid incident window: $SCAN_START -> $SCAN_END" >&2
exit 1
fi
START_MARK="$OUT_DIR/.window-start"
END_MARK="$OUT_DIR/.window-end"
touch -d "$SCAN_START" "$START_MARK" || exit 1
touch -d "$SCAN_END" "$END_MARK" || exit 1
section "scan metadata"
{
echo "scanner_version=$VERSION"
echo "scan_time=$(date '+%F %T %z')"
echo "scan_window=$SCAN_START -> $SCAN_END"
echo "mode=$MODE"
echo "hostname=$HOST_NAME"
uname -a
test -r /etc/redhat-release && cat /etc/redhat-release
test -r /etc/centos-release && cat /etc/centos-release
uptime
echo "-- addresses --"
if have ip; then ip -4 addr show; else ifconfig -a 2>/dev/null; fi
echo "-- routes --"
if have ip; then ip route show; else route -n 2>/dev/null; fi
echo "-- time --"
date
hwclock 2>/dev/null || true
} >> "$RAW" 2>&1
section "accounts and local sessions"
{
stat /etc/passwd /etc/shadow /etc/group /etc/sudoers 2>/dev/null
echo "-- UID 0 accounts --"
awk -F: '$3==0 {print}' /etc/passwd
echo "-- current sessions --"
who -a
echo "-- recent sessions --"
last -Fai 2>/dev/null | head -200
} >> "$RAW" 2>&1
EXTRA_UID0="$(awk -F: '$3==0 && $1!="root" {print $1}' /etc/passwd 2>/dev/null | tr '\n' ' ')"
if test -n "$EXTRA_UID0"; then
finding HIGH persistence account "Additional UID 0 account(s): $EXTRA_UID0"
fi
section "targeted RPM and malicious package evidence"
IRQ_RPM_BAD=0
if have rpm; then
echo "-- relevant installed packages --" >> "$RAW"
rpm -qa --qf '%{NAME}\t%{VERSION}-%{RELEASE}\t%{ARCH}\t%{INSTALLTIME}\n' 2>/dev/null \
| grep -Eai '^(aliyun|irqbalance|rng-tools|kernel-devel|elfutils-libelf-devel)' >> "$RAW"
echo "-- recent RPM installs --" >> "$RAW"
rpm -qa --last 2>/dev/null | head -200 >> "$RAW"
if rpm -q irqbalance >/dev/null 2>&1; then
rpm -qi irqbalance >> "$RAW" 2>&1
IRQ_VERIFY="$(rpm -V irqbalance 2>&1 || true)"
printf '%s\n' "$IRQ_VERIFY" >> "$RAW"
if printf '%s\n' "$IRQ_VERIFY" | grep -q '/usr/sbin/irqbalance'; then
IRQ_RPM_BAD=1
finding CRITICAL execution integrity "RPM verification failed for /usr/sbin/irqbalance: $IRQ_VERIFY"
fi
fi
if rpm -q aliyun-sys-assist >/dev/null 2>&1; then
finding CRITICAL persistence package "Unsigned campaign package aliyun-sys-assist is installed"
rpm -qi aliyun-sys-assist > "$ARTIFACTS/package-metadata/aliyun-sys-assist-rpm-info.txt" 2>&1
rpm -ql aliyun-sys-assist > "$ARTIFACTS/package-metadata/aliyun-sys-assist-files.txt" 2>&1
rpm -q --scripts aliyun-sys-assist > "$ARTIFACTS/package-metadata/aliyun-sys-assist-scripts.txt" 2>&1
rpm -V aliyun-sys-assist > "$ARTIFACTS/package-metadata/aliyun-sys-assist-verify.txt" 2>&1 || true
cat "$ARTIFACTS/package-metadata/aliyun-sys-assist-rpm-info.txt" >> "$RAW"
cat "$ARTIFACTS/package-metadata/aliyun-sys-assist-scripts.txt" >> "$RAW"
_pkg_epoch="$(rpm -q aliyun-sys-assist --qf '%{INSTALLTIME}' 2>/dev/null || true)"
if test -n "$_pkg_epoch"; then
_pkg_time="$(date -d "@$_pkg_epoch" '+%F %T %z' 2>/dev/null || echo "$_pkg_epoch")"
event "$_pkg_time" persistence rpm aliyun-sys-assist "unsigned package installed"
fi
_sig="$(rpm -qi aliyun-sys-assist 2>/dev/null | grep -i '^Signature' || true)"
if printf '%s' "$_sig" | grep -qi '(none)'; then
finding CRITICAL execution signature "aliyun-sys-assist RPM has no package signature: $_sig"
fi
fi
for _build_pkg in $(rpm -qa 2>/dev/null | grep -E '^(kernel-devel|elfutils-libelf-devel)'); do
_build_epoch="$(rpm -q "$_build_pkg" --qf '%{INSTALLTIME}' 2>/dev/null || echo 0)"
if test "$_build_epoch" -ge "$START_EPOCH" 2>/dev/null \
&& test "$_build_epoch" -le "$END_EPOCH" 2>/dev/null; then
_build_time="$(date -d "@$_build_epoch" '+%F %T %z' 2>/dev/null || echo "$_build_epoch")"
finding HIGH execution prerequisite "Build prerequisite installed during incident window: $_build_pkg at $_build_time"
event "$_build_time" execution rpm build-prerequisite "$_build_pkg"
fi
done
fi
section "known and campaign-related files"
for _path in \
/usr/sbin/irqbalance \
/usr/lib64/libnuma_hint.so \
/usr/lib/libnuma_hint.so \
/usr/sbin/aliyun-sys-assist-setup \
/usr/lib/aliyun-sys-assist-payload/AliyunSysAssist \
/usr/lib/aliyun-sys-assist-payload/core.so \
/usr/lib/aliyun-sys-assist-payload/.cfg.example \
/usr/local/share/aliyun-sys-assist/AliyunSysAssist \
/usr/local/share/aliyun-sys-assist/.cfg \
/usr/local/share/aliyun-sys-assist/.epcache \
/usr/local/share/aliyun-sys-assist/.helper.lock \
/usr/local/share/aliyun-sys-assist/.helper.alive \
/tmp/dbg /tmp/dbg-el6 /tmp/sys.rpm /tmp/elf.rpm /tmp/kd.rpm \
/tmp/v2_rpm.log /tmp/v2_rpm.exit; do
file_evidence "$_path" campaign-target
done
section "static indicators extracted from campaign binaries"
for _binary in \
/usr/sbin/irqbalance \
/usr/sbin/aliyun-sys-assist-setup \
/usr/lib/aliyun-sys-assist-payload/AliyunSysAssist \
/usr/lib/aliyun-sys-assist-payload/core.so \
/usr/local/share/aliyun-sys-assist/AliyunSysAssist \
/usr/lib64/libnuma_hint.so /usr/lib/libnuma_hint.so \
/tmp/dbg /tmp/dbg-el6; do
test -r "$_binary" || continue
_binary_hash="$(hash_value "$_binary")"
_binary_label="$(hash_label "$_binary_hash")"
if test -z "$_binary_label"; then
case "$_binary" in
/usr/sbin/irqbalance)
test "${IRQ_RPM_BAD:-0}" -eq 1 || continue
_binary_label="altered irqbalance candidate" ;;
/usr/sbin/aliyun-sys-assist-setup|/usr/lib/aliyun-sys-assist-payload/*|/usr/local/share/aliyun-sys-assist/*|/tmp/dbg|/tmp/dbg-el6)
_binary_label="campaign-path candidate" ;;
*) continue ;;
esac
fi
_binary_name="$(basename "$_binary" | tr -c 'A-Za-z0-9._-' '_')"
_indicator_file="$ARTIFACTS/binary-indicators/${_binary_hash}-${_binary_name}.txt"
if have strings; then
strings -a "$_binary" 2>/dev/null \
| grep -Eai 'https?://|([0-9]{1,3}\.){3}[0-9]{1,3}|[A-Za-z0-9._-]+\.(com|net|org|cn)([:/]|$)|authorized_keys|HISTFILE|/tmp/|socket|curl|wget' \
| sort -u > "$_indicator_file"
cat "$_indicator_file" >> "$ENDPOINTS"
fi
if have readelf; then
readelf -h -n -d "$_binary" >> "$RAW" 2>&1
fi
done
sort -u "$ENDPOINTS" -o "$ENDPOINTS" 2>/dev/null || true
if test -d /usr/local/share/aliyun-sys-assist; then
finding CRITICAL persistence directory "Malicious lookalike directory /usr/local/share/aliyun-sys-assist exists"
find /usr/local/share/aliyun-sys-assist -xdev -printf '%M %u:%g %TY-%Tm-%Td %TH:%TM:%TS %s %p\n' \
>> "$RAW" 2>/dev/null
if test -r /usr/local/share/aliyun-sys-assist/.cfg && have strings; then
echo "-- strings from malicious .cfg --" >> "$RAW"
strings -a /usr/local/share/aliyun-sys-assist/.cfg | head -200 >> "$RAW"
if strings -a /usr/local/share/aliyun-sys-assist/.cfg | grep -Eq "$IOC_TEXT_REGEX"; then
finding CRITICAL command_control configuration "aliyun-sys-assist .cfg contains campaign endpoint/key indicators"
fi
fi
fi
section "running process correlation"
MATCHED_PIDS=""
CAMPAIGN_PIDS=""
IRQ_PIDS=""
for _proc in /proc/[0-9]*; do
test -d "$_proc" || continue
_pid="${_proc#/proc/}"
_exe="$(readlink "$_proc/exe" 2>/dev/null || true)"
_comm="$(cat "$_proc/comm" 2>/dev/null || true)"
_cmd="$(tr '\0' ' ' < "$_proc/cmdline" 2>/dev/null || true)"
_maps_hit="$(grep -E 'libnuma_hint\.so|aliyun-sys-assist|/tmp/dbg' "$_proc/maps" 2>/dev/null | head -20 || true)"
_digest=""
test -r "$_proc/exe" && _digest="$(hash_value "$_proc/exe")"
_label="$(hash_label "$_digest")"
_match=0
_campaign_match=0
case "$_comm $_exe $_cmd $_maps_hit $_label" in
*irqbalance*|*AliyunSysAssist*|*aliyun-sys-assist*|*"/tmp/dbg"*|*libnuma_hint*|*"dbg payload"*|*"malicious "*)
_match=1; _campaign_match=1 ;;
*"(deleted)"*) _match=1 ;;
rngd*) _match=1 ;;
esac
test "$_match" -eq 1 || continue
MATCHED_PIDS="$MATCHED_PIDS $_pid"
test "$_campaign_match" -eq 1 && CAMPAIGN_PIDS="$CAMPAIGN_PIDS $_pid"
case "$_comm $_cmd" in *irqbalance*) IRQ_PIDS="$IRQ_PIDS $_pid" ;; esac
_ppid="$(awk '/^PPid:/ {print $2}' "$_proc/status" 2>/dev/null || true)"
_user="$(ps -p "$_pid" -o user= 2>/dev/null | awk '{print $1}')"
_start="$(ps -p "$_pid" -o lstart= 2>/dev/null | sed 's/^[[:space:]]*//')"
printf '%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n' \
"$HOST_NAME" "$_pid" "$_ppid" "$_user" "$(sanitize "$_start")" \
"$(sanitize "$_comm")" "$(sanitize "$_exe")" "$_digest" "$(sanitize "$_cmd")" >> "$PROCESSES"
_proc_report="$ARTIFACTS/processes/pid-${_pid}.txt"
{
ps -o user,pid,ppid,lstart,etime,stat,cmd -p "$_pid"
echo "comm=$_comm"
echo "exe=$_exe"
echo "sha256=$_digest"
echo "cmdline=$_cmd"
echo "-- maps IOC subset --"
printf '%s\n' "$_maps_hit"
echo "-- file descriptors --"
ls -l "$_proc/fd"
echo "-- limits --"
cat "$_proc/limits" 2>/dev/null
} > "$_proc_report" 2>&1
if test "$_campaign_match" -eq 1 && test -r "$_proc/exe"; then
_proc_size="$(stat -c %s "$_proc/exe" 2>/dev/null || echo 0)"
if test "$_proc_size" -le 52428800 2>/dev/null; then
copy_artifact "$_proc/exe" "$ARTIFACTS/processes/pid-${_pid}-exe.bin"
else
echo "process executable not copied due to size: pid=$_pid size=$_proc_size exe=$_exe" >> "$RAW"
fi
fi
test -n "$_digest" && classify_hash "$_digest" "/proc/$_pid/exe ($_exe)"
if test -n "$_label"; then
finding CRITICAL execution process "PID $_pid runs $_label; comm=$_comm exe=$_exe"
fi
case "$_exe" in
/tmp/dbg|/tmp/dbg-el6|"/tmp/dbg (deleted)"|"/tmp/dbg-el6 (deleted)")
finding CRITICAL execution process "PID $_pid runs campaign payload $_exe; comm=$_comm" ;;
*"(deleted)"*)
finding HIGH defense_evasion process "PID $_pid runs deleted executable $_exe; comm=$_comm" ;;
esac
case "$_comm $_exe $_cmd" in
*AliyunSysAssist*|*aliyun-sys-assist*)
finding CRITICAL persistence process "PID $_pid is active malicious AliyunSysAssist component; exe=$_exe" ;;
esac
if test -n "$_maps_hit" && printf '%s' "$_maps_hit" | grep -q 'libnuma_hint\.so'; then
finding CRITICAL execution process "PID $_pid maps malicious libnuma_hint.so; exe=$_exe"
fi
event "$_start" execution process "$_comm" "pid=$_pid ppid=$_ppid exe=$_exe sha256=$_digest"
done
IRQ_COUNT="$(printf '%s\n' $IRQ_PIDS 2>/dev/null | awk 'NF {n++} END {print n+0}')"
if test "$IRQ_COUNT" -gt 1; then
finding HIGH execution process "Multiple irqbalance-like processes are active ($IRQ_COUNT):$IRQ_PIDS"
fi
section "network, C2 and local control sockets"
NET_ALL=""
UNIX_ALL=""
if have netstat; then
NET_ALL="$(netstat -antup 2>/dev/null || true)"
UNIX_ALL="$(netstat -xap 2>/dev/null || true)"
elif have ss; then
NET_ALL="$(ss -antup 2>/dev/null || true)"
UNIX_ALL="$(ss -xap 2>/dev/null || true)"
fi
printf '%s\n' "$NET_ALL" >> "$RAW"
printf '%s\n' "$UNIX_ALL" >> "$RAW"
if printf '%s\n' "$UNIX_ALL" | grep -Fq 'hpgoc2.oss.v2.core'; then
_sock_hit="$(printf '%s\n' "$UNIX_ALL" | grep -F 'hpgoc2.oss.v2.core' | head -5)"
finding CRITICAL command_control socket "Known campaign Unix socket is active: $_sock_hit"
event "$(date '+%F %T %z')" command_control socket hpgoc2.oss.v2.core "$_sock_hit"
fi
if printf '%s\n' "$NET_ALL" | grep -Eq '101\.201\.148\.142|8\.217\.173\.211'; then
_net_hit="$(printf '%s\n' "$NET_ALL" | grep -E '101\.201\.148\.142|8\.217\.173\.211' | head -10)"
finding CRITICAL command_control network "Active connection to known campaign IP: $_net_hit"
event "$(date '+%F %T %z')" command_control network known-c2 "$_net_hit"
fi
if have netstat; then
netstat -antp 2>/dev/null | awk -v host="$HOST_NAME" '
BEGIN {OFS="\t"}
$1 ~ /^tcp/ && $6 == "ESTABLISHED" {
remote=$5; ip=remote; sub(/:[^:]*$/, "", ip)
if (ip ~ /^::ffff:/) sub(/^::ffff:/, "", ip)
private=(ip ~ /^10\./ || ip ~ /^127\./ || ip ~ /^169\.254\./ ||
ip ~ /^192\.168\./ || ip ~ /^0\.0\.0\.0$/ ||
ip ~ /^172\.(1[6-9]|2[0-9]|3[01])\./)
if (!private && ip ~ /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/)
print host,$1,$4,$5,$6,$7
}
' >> "$CONNECTIONS"
elif have ss; then
ss -antp 2>/dev/null | awk -v host="$HOST_NAME" '
BEGIN {OFS="\t"}
$1 == "ESTAB" {
remote=$5; ip=remote; sub(/:[^:]*$/, "", ip)
private=(ip ~ /^10\./ || ip ~ /^127\./ || ip ~ /^169\.254\./ ||
ip ~ /^192\.168\./ || ip ~ /^0\.0\.0\.0$/ ||
ip ~ /^172\.(1[6-9]|2[0-9]|3[01])\./)
if (!private && ip ~ /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/)
print host,"tcp",$4,$5,$1,$6
}
' >> "$CONNECTIONS"
fi
PUBLIC_COUNT="$(awk 'NR>1 {n++} END {print n+0}' "$CONNECTIONS")"
test "$PUBLIC_COUNT" -gt 0 && finding INFO discovery network "Recorded $PUBLIC_COUNT established public connection(s) for review"
for _pid in $CAMPAIGN_PIDS; do
if have netstat; then
_pid_net="$(printf '%s\n' "$NET_ALL" | grep -E "[[:space:]]${_pid}/" || true)"
else
_pid_net="$(printf '%s\n' "$NET_ALL" | grep -E "pid=${_pid}[,)]|pid=\"${_pid}\"" || true)"
fi
if test -n "$_pid_net"; then
printf '\n-- network for matched PID %s --\n%s\n' "$_pid" "$_pid_net" >> "$RAW"
finding HIGH command_control network "Matched PID $_pid has active network connection(s): $_pid_net"
fi
done
section "SSH keys and credential material"
for _ssh_dir in /root/.ssh /home/*/.ssh; do
test -d "$_ssh_dir" || continue
find "$_ssh_dir" -maxdepth 2 -type f \( -name authorized_keys -o -name authorized_keys2 \) 2>/dev/null \
| while IFS= read -r _key_file; do
echo "-- $_key_file --" >> "$RAW"
stat "$_key_file" >> "$RAW" 2>&1
_key_copy="$(printf '%s' "$_key_file" | sed 's#/#_#g')"
copy_artifact "$_key_file" "$ARTIFACTS/authorized-keys/${_key_copy}"
_key_info="$(ssh-keygen -E sha256 -lf "$_key_file" 2>/dev/null || ssh-keygen -lf "$_key_file" 2>/dev/null || true)"
printf '%s\n' "$_key_info" >> "$RAW"
if printf '%s\n' "$_key_info" | grep -Fq "$BAD_KEY_SHA256" \
|| grep -Fq "$PIVOT_KEY_FRAGMENT" "$_key_file" 2>/dev/null; then
finding CRITICAL persistence ssh_key "Known 159-generated attacker key is authorized in $_key_file"
fi
if grep -Fq "$CURSOR_KEY_FRAGMENT" "$_key_file" 2>/dev/null \
|| grep -Fq 'cursor-agent-010' "$_key_file" 2>/dev/null; then
finding CRITICAL persistence ssh_key "Known cursor-agent-010 key is authorized in $_key_file"
fi
done
done
for _ssh_dir in /root/.ssh /home/*/.ssh; do
test -d "$_ssh_dir" || continue
find "$_ssh_dir" -maxdepth 2 -type f \( -name id_rsa -o -name id_dsa -o -name id_ecdsa -o -name id_ed25519 \) 2>/dev/null \
| while IFS= read -r _private_key; do
_key_mtime="$(stat -c %Y "$_private_key" 2>/dev/null || echo 0)"
_key_hash="$(hash_value "$_private_key")"
echo "private_key=$_private_key mtime_epoch=$_key_mtime sha256=$_key_hash" >> "$RAW"
stat "$_private_key" >> "$RAW" 2>&1
if test "$_key_mtime" -ge "$START_EPOCH" 2>/dev/null \
&& test "$_key_mtime" -le "$END_EPOCH" 2>/dev/null; then
_key_time="$(date -d "@$_key_mtime" '+%F %T %z' 2>/dev/null || echo "$_key_mtime")"
finding HIGH credential_access ssh_private_key "Private SSH key changed during incident window: $_private_key at $_key_time sha256=$_key_hash"
event "$_key_time" credential_access filesystem ssh-private-key "$_private_key sha256=$_key_hash"
fi
done
done
section "SSH authentication timeline"
if ls /var/log/secure* >/dev/null 2>&1; then
zgrep -hE 'sshd.*Accepted (publickey|password)' /var/log/secure* 2>/dev/null \
| grep -E '^Sep[[:space:]]+(10|11|12)[[:space:]]' > "$SSH_SUCCESS"
cat "$SSH_SUCCESS" >> "$RAW"
_from_159="$(grep -E 'Accepted (publickey|password).* from 172\.18\.172\.159 ' "$SSH_SUCCESS" || true)"
if test -n "$_from_159"; then
finding CRITICAL lateral_movement ssh "Successful SSH authentication from compromised pivot 172.18.172.159: $(printf '%s\n' "$_from_159" | head -8)"
fi
_bad_fp_log="$(grep -F "$BAD_KEY_SHA256" "$SSH_SUCCESS" || true)"
if test -n "$_bad_fp_log"; then
finding CRITICAL lateral_movement ssh "Known attacker key fingerprint used successfully: $(printf '%s\n' "$_bad_fp_log" | head -8)"
fi
while IFS= read -r _ssh_line; do
test -n "$_ssh_line" || continue
_ssh_raw_time="$(printf '%s' "$_ssh_line" | awk '{print $1" "$2" "$3}')"
_ssh_stamp="$(date -d "2026 $_ssh_raw_time" '+%F %T %z' 2>/dev/null || echo "2026 $_ssh_raw_time")"
event "$_ssh_stamp" lateral_movement secure-log ssh-accepted "$_ssh_line"
done < "$SSH_SUCCESS"
else
finding INFO discovery logging "No /var/log/secure* files were available"
fi
section "Aliyun CLI and possible AccessKey exposure"
if have aliyun; then
_aliyun_path="$(command -v aliyun)"
file_evidence "$_aliyun_path" aliyun-cli
fi
for _aliyun_cfg in /root/.aliyun/config.json /home/*/.aliyun/config.json; do
test -f "$_aliyun_cfg" || continue
stat "$_aliyun_cfg" >> "$RAW" 2>&1
echo "aliyun_cli_config=$_aliyun_cfg sha256=$(hash_value "$_aliyun_cfg")" >> "$RAW"
_ak_ids="$(grep -Eo 'LTAI[A-Za-z0-9]+' "$_aliyun_cfg" 2>/dev/null | sort -u | tr '\n' ' ')"
finding HIGH credential_access cloud_credential "Aliyun CLI credential file exists on compromised host: $_aliyun_cfg access_key_ids=$_ak_ids"
if grep -Fq "$KNOWN_AK_ID" "$_aliyun_cfg" 2>/dev/null; then
finding CRITICAL credential_access cloud_credential "Known compromised AccessKey ID is stored in $_aliyun_cfg"
fi
done
for _hist_root in /root/.bash_history /root/.zsh_history /home/*/.bash_history /home/*/.zsh_history; do
test -f "$_hist_root" || continue
if grep -Eq "$IOC_TEXT_REGEX|aliyun[[:space:]].*(RunCommand|ecs)|access[_-]?key" "$_hist_root" 2>/dev/null; then
finding HIGH credential_access shell_history "Cloud/campaign references found in $_hist_root; inspect locally for leaked credentials"
echo "history_ioc_file=$_hist_root" >> "$RAW"
fi
done
section "official Cloud Assistant inventory"
for _official_root in /usr/local/share/aliyun-assist /opt/local/share/aliyun-assist; do
test -d "$_official_root" || continue
echo "-- official root $_official_root --" >> "$RAW"
stat "$_official_root" >> "$RAW" 2>&1
find "$_official_root" -maxdepth 4 -type f \
\( -name aliyun-service -o -name aliyun_assist_update -o -name assist_daemon \
-o -name hash_file -o -name version -o -name region-id \) \
-printf '%M %u:%g %TY-%Tm-%Td %TH:%TM:%TS %s %p\n' >> "$RAW" 2>/dev/null
find "$_official_root" -maxdepth 4 -type f \
\( -name aliyun-service -o -name aliyun_assist_update -o -name assist_daemon \
-o -name hash_file \) 2>/dev/null | while IFS= read -r _official_file; do
echo "official_file=$_official_file sha256=$(hash_value "$_official_file")" >> "$RAW"
if test "$(basename "$_official_file")" = hash_file; then
_hash_copy="$(printf '%s' "$_official_file" | sed 's#/#_#g')"
copy_artifact "$_official_file" "$ARTIFACTS/package-metadata/${_hash_copy}"
fi
done
done
ps -efww 2>/dev/null | grep -E '[a]liyun-service|[a]ssist_daemon' >> "$RAW"
if have rpm; then
rpm -qa 2>/dev/null | grep -Eai '^aliyun[_-]assist|cloud.*assist' >> "$RAW"
fi
section "Cloud Assistant command artifacts"
for _assist_root in /usr/local/share/aliyun-assist/work/script /opt/local/share/aliyun-assist/work/script; do
test -d "$_assist_root" || continue
find "$_assist_root" -type f 2>/dev/null | while IFS= read -r _script; do
_script_mtime_epoch="$(stat -c %Y "$_script" 2>/dev/null || echo 0)"
_script_mtime="$(date -d "@$_script_mtime_epoch" '+%F %T %z' 2>/dev/null || echo "$_script_mtime_epoch")"
_script_hash="$(hash_value "$_script")"
_classification="inventory"
_matched=0
if grep -Eq "$IOC_TEXT_REGEX" "$_script" 2>/dev/null; then
_classification="known-ioc"
_matched=1
finding CRITICAL execution cloud_assist "Cloud Assistant script contains known campaign IOC: $_script"
elif grep -Eq "$IOC_EXEC_REGEX" "$_script" 2>/dev/null; then
_classification="sensitive-command"
_matched=1
finding HIGH execution cloud_assist "Cloud Assistant script contains sensitive execution/persistence command: $_script"
fi
if test "$_script_mtime_epoch" -ge "$START_EPOCH" 2>/dev/null \
&& test "$_script_mtime_epoch" -le "$END_EPOCH" 2>/dev/null; then
_matched=1
test "$_classification" = inventory && _classification="incident-window"
fi
printf '%s\t%s\t%s\t%s\t%s\n' "$HOST_NAME" "$_script_mtime" "$_script_hash" "$_script" "$_classification" >> "$SCRIPTS"
if test "$_matched" -eq 1; then
_script_name="$(basename "$_script")"
copy_artifact "$_script" "$ARTIFACTS/cloud-assist-scripts/${_script_name}"
echo "-- cloud assist script $_script --" >> "$RAW"
stat "$_script" >> "$RAW" 2>&1
sed -n '1,400p' "$_script" >> "$RAW" 2>&1
event "$_script_mtime" execution cloud-assist-script "$_classification" "$_script sha256=$_script_hash"
fi
done
done
section "persistence locations and IOC references"
for _persist_root in \
/etc/systemd/system /usr/lib/systemd/system /lib/systemd/system \
/etc/init.d /etc/rc.d /etc/cron.d /etc/cron.daily /etc/cron.hourly \
/var/spool/cron /etc/profile.d /etc/ld.so.preload; do
test -e "$_persist_root" || continue
grep -RIlE "$IOC_TEXT_REGEX" "$_persist_root" >> "$RAW" 2>/dev/null
done
_persist_hits="$(grep -RIlE "$IOC_TEXT_REGEX" \
/etc/systemd/system /usr/lib/systemd/system /lib/systemd/system \
/etc/init.d /etc/rc.d /etc/cron.d /var/spool/cron /etc/profile.d \
2>/dev/null | head -100 || true)"
if test -n "$_persist_hits"; then
finding CRITICAL persistence startup "Campaign IOC found in persistence file(s): $_persist_hits"
fi
if test -s /etc/ld.so.preload; then
cat /etc/ld.so.preload >> "$RAW" 2>&1
finding HIGH persistence loader "/etc/ld.so.preload is non-empty; review for userland hooking"
fi
if have systemctl; then
systemctl status irqbalance --no-pager >> "$RAW" 2>&1
systemctl list-unit-files --no-pager 2>/dev/null | grep -Ei 'aliyun|assist|irqbalance|rngd|nvme' >> "$RAW"
elif have chkconfig; then
chkconfig --list 2>/dev/null | grep -Ei 'aliyun|assist|irqbalance|rngd|nvme' >> "$RAW"
fi
section "recent files by ctime and mtime"
RECENT_ROOTS="/usr/sbin /usr/local /usr/lib64 /usr/lib /etc /tmp /var/tmp /dev/shm /lib/modules/$(uname -r)"
if test "$MODE" = deep; then
RECENT_ROOTS="$RECENT_ROOTS /usr/bin /bin /sbin /lib /lib64 /opt"
fi
record_recent() {
local _recent_path _time_type _size _mode _owner _recent_time _recent_hash
_recent_path="$1"
_time_type="$2"
test -f "$_recent_path" || return 0
_size="$(stat -c %s "$_recent_path" 2>/dev/null || echo 0)"
_mode="$(stat -c %A "$_recent_path" 2>/dev/null || echo unknown)"
_owner="$(stat -c '%U:%G' "$_recent_path" 2>/dev/null || echo unknown)"
if test "$_time_type" = ctime; then
_recent_time="$(stat -c %z "$_recent_path" 2>/dev/null || true)"
else
_recent_time="$(stat -c %y "$_recent_path" 2>/dev/null || true)"
fi
_recent_hash=""
if test "$_size" -le 20971520 2>/dev/null && test -r "$_recent_path"; then
_recent_hash="$(hash_value "$_recent_path")"
test -n "$_recent_hash" && classify_hash "$_recent_hash" "$_recent_path"
fi
printf '%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n' \
"$HOST_NAME" "$_time_type" "$(sanitize "$_recent_time")" "$_mode" "$_owner" \
"$_size" "$_recent_hash" "$(sanitize "$_recent_path")" >> "$FILES"
case "$_recent_path" in
*/irqbalance|*aliyun-sys-assist*|*libnuma_hint.so|*/tmp/dbg|*/tmp/dbg-el6|*/authorized_keys|*/id_rsa|*/id_rsa.pub)
event "$_recent_time" defense_evasion filesystem "${_time_type}-in-window" "$_recent_path sha256=$_recent_hash"
;;
esac
}
for _recent_root in $RECENT_ROOTS; do
test -d "$_recent_root" || continue
find "$_recent_root" -xdev -type f -cnewer "$START_MARK" ! -cnewer "$END_MARK" -print0 2>/dev/null \
| while IFS= read -r -d '' _recent_file; do record_recent "$_recent_file" ctime; done
find "$_recent_root" -xdev -type f -newer "$START_MARK" ! -newer "$END_MARK" -print0 2>/dev/null \
| while IFS= read -r -d '' _recent_file; do record_recent "$_recent_file" mtime; done
done
section "kernel and module evidence"
{
echo "-- loaded modules --"
if have lsmod; then lsmod; else cat /proc/modules 2>/dev/null; fi
echo "-- module files changed in incident window --"
if test -d "/lib/modules/$(uname -r)"; then
find "/lib/modules/$(uname -r)" -xdev -type f \
-cnewer "$START_MARK" ! -cnewer "$END_MARK" \
-printf '%CY-%Cm-%Cd %CH:%CM:%CS %s %p\n' 2>/dev/null
fi
echo "-- recent kernel messages --"
dmesg 2>/dev/null | tail -500
} >> "$RAW" 2>&1
_module_changes=""
if test -d "/lib/modules/$(uname -r)"; then
_module_changes="$(find "/lib/modules/$(uname -r)" -xdev -type f \
-cnewer "$START_MARK" ! -cnewer "$END_MARK" -print 2>/dev/null | head -50)"
fi
if test -n "$_module_changes"; then
finding HIGH persistence kernel_module "Kernel module file(s) changed during incident window: $_module_changes"
fi
section "IOC references in selected data locations"
for _search_root in \
/usr/local/share/aliyun-assist/work/script \
/usr/local/share/aliyun-sys-assist \
/opt/local/share/aliyun-assist/work/script \
/root/.aliyun /home/*/.aliyun /root/.ssh /home/*/.ssh \
/root/.bash_history /home/*/.bash_history; do
test -e "$_search_root" || continue
grep -RIlE "$IOC_TEXT_REGEX" "$_search_root" >> "$RAW" 2>/dev/null
done
section "scan limitations"
cat >> "$RAW" <<'EOF'
This live-host scan cannot prove that a root-compromised kernel, C library,
command binary, RPM database, logs, or timestamps are trustworthy. Attackers
can remove logs, forge mtime, hide processes, or modify verification tools.
ctime and multiple independent evidence sources are collected to reduce, not
eliminate, that limitation. Offline disk/memory forensics or rebuild remains
the trust-restoring action for confirmed hosts.
EOF
CRITICAL_COUNT="$(awk -F '\t' 'NR>1 && $2=="CRITICAL" {n++} END {print n+0}' "$FINDINGS")"
HIGH_COUNT="$(awk -F '\t' 'NR>1 && $2=="HIGH" {n++} END {print n+0}' "$FINDINGS")"
{
echo "Scanner: server_incident_scan_v3.sh $VERSION"
echo "Host: $HOST_NAME"
echo "Scan time: $(date '+%F %T %z')"
echo "Incident window: $SCAN_START -> $SCAN_END"
echo "Mode: $MODE"
echo "Output: $OUT_DIR"
echo "Critical findings: $CRITICAL_COUNT"
echo "High findings: $HIGH_COUNT"
if test "$CRITICAL_COUNT" -gt 0; then
echo "Assessment: CONFIRMED/HIGH-CONFIDENCE COMPROMISE INDICATORS FOUND"
elif test "$HIGH_COUNT" -gt 0; then
echo "Assessment: SUSPICIOUS - MANUAL REVIEW REQUIRED"
else
echo "Assessment: NO KNOWN IOC FOUND (NOT PROOF OF SAFETY)"
fi
echo
echo "Detected stages:"
awk -F '\t' 'NR>1 && ($2=="CRITICAL" || $2=="HIGH") {print $3}' "$FINDINGS" | sort -u | sed 's/^/ - /'
echo
if have column; then
column -t -s "$(printf '\t')" "$FINDINGS"
else
cat "$FINDINGS"
fi
} > "$SUMMARY"
cat > "$OUT_DIR/README.txt" <<EOF
server_incident_scan_v3.sh $VERSION
summary.txt Human-readable result
findings.tsv Cross-host findings with attack stages
chain_events.tsv Mergeable host timeline
processes.tsv Matched process inventory and hashes
public_remote_connections.tsv Established public peers for manual review
ssh_success.log Successful SSH/session entries around incident
recent_files.tsv ctime/mtime incident-window file inventory
cloud_assist_scripts.tsv Cloud Assistant command-script inventory
candidate_endpoints.txt Strings-derived endpoint candidates from known malware
evidence.txt Detailed raw evidence
artifacts/ Copies of selected evidence; mode 0700/0600
This scan performed no remediation. Reading files may update access time on
filesystems using strict atime. Treat copied executable artifacts as malware.
EOF
chmod -R go-rwx "$OUT_DIR" 2>/dev/null
if have sha256sum; then
(
cd "$OUT_DIR" || exit 1
find . -type f ! -name checksums.sha256 -print | sort | while IFS= read -r _manifest_file; do
sha256sum "$_manifest_file"
done
) > "$OUT_DIR/checksums.sha256"
fi
cat "$SUMMARY"
echo
echo "Evidence directory: $OUT_DIR"
echo "No processes, services, files, firewall rules, packages, repositories, or accounts were changed."
exit 0
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment