| Server IP : 85.143.209.190 / Your IP : 216.73.217.12 Web Server : Apache/2.4.63 (Ubuntu) System : Linux 49083.simplecloud.ru 5.4.0-205-generic #225-Ubuntu SMP Fri Jan 10 22:23:35 UTC 2025 x86_64 User : vozdvizhenka37 ( 1083) PHP Version : 7.4.33 Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare, MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : ON Directory : /home/ |
Upload File : |
#!/usr/bin/env bash
#
# wp_incident_scan.sh
# Read-only scanner for WordPress infections under /home or another base dir.
#
# Usage:
# sudo ./wp_incident_scan.sh /home
# sudo ./wp_incident_scan.sh /home /root/wp-scan-report
#
# Requires Linux with GNU find/grep. If wp-cli is installed, it will also run
# WordPress integrity checks.
set -u
umask 077
BASE_DIR="${1:-/home}"
REPORT_DIR="${2:-$HOME/wp-incident-scan-$(date +%Y%m%d-%H%M%S)}"
mkdir -p "$REPORT_DIR"
chmod 700 "$REPORT_DIR" 2>/dev/null || true
SUMMARY="$REPORT_DIR/00-summary.txt"
LOG="$REPORT_DIR/scan.log"
HIGH="$REPORT_DIR/10-high-risk-php.txt"
COOKIE_SHELL="$REPORT_DIR/15-cookie-variable-shell.txt"
MEDIUM="$REPORT_DIR/20-medium-risk-php.txt"
SUSPECT_PATHS="$REPORT_DIR/30-suspicious-files.txt"
RECENT="$REPORT_DIR/40-recently-modified.txt"
HTACCESS="$REPORT_DIR/50-htaccess-ini.txt"
WPCLI="$REPORT_DIR/60-wp-cli-integrity.txt"
WP_LIST="$REPORT_DIR/wp-installs.txt"
for f in "$SUMMARY" "$LOG" "$HIGH" "$COOKIE_SHELL" "$MEDIUM" \
"$SUSPECT_PATHS" "$RECENT" "$HTACCESS" "$WPCLI" "$WP_LIST"; do
: > "$f"
done
log() {
printf '%s\n' "$*" | tee -a "$LOG" >> "$SUMMARY"
}
log "=== WordPress incident scan ==="
log "Started: $(date)"
log "Base dir: $BASE_DIR"
log "Report dir: $REPORT_DIR"
if [ ! -d "$BASE_DIR" ]; then
log "ERROR: base dir $BASE_DIR does not exist."
exit 1
fi
# Detect WordPress installs by wp-load.php
find "$BASE_DIR" -type f -name wp-load.php -printf '%h\n' 2>/dev/null | sort -u > "$WP_LIST"
if [ ! -s "$WP_LIST" ]; then
log "No wp-load.php found under $BASE_DIR; scanning base dir anyway."
echo "$BASE_DIR" > "$WP_LIST"
fi
log "WordPress install roots detected:"
sed 's/^/ /' "$WP_LIST" | tee -a "$LOG" >> "$SUMMARY"
# High-risk PHP patterns
cat > "$REPORT_DIR/high.ere" <<'EOF'
(eval|assert)[[:space:]]*\([[:space:]]*(base64_decode|gzinflate|gzuncompress|gzdecode|str_rot13|rawurldecode|hex2bin|convert_uudecode|strrev)
(eval|assert)[[:space:]]*\([[:space:]]*\$_(GET|POST|REQUEST|COOKIE|SERVER|FILES)
base64_decode[[:space:]]*\([[:space:]]*\$_(GET|POST|REQUEST|COOKIE|SERVER|FILES)
gzinflate[[:space:]]*\([[:space:]]*base64_decode
gzuncompress[[:space:]]*\([[:space:]]*base64_decode
gzdecode[[:space:]]*\([[:space:]]*base64_decode
str_rot13[[:space:]]*\([[:space:]]*base64_decode
preg_replace[[:space:]]*\([^,]*['"][^'"]*/[a-zA-Z]*e[a-zA-Z]*['"]
create_function[[:space:]]*\(
\$\{[[:space:]]*['"]_(GET|POST|REQUEST|COOKIE|SERVER|FILES|ENV|SESSION)['"]
\$\{[[:space:]]*\$[A-Za-z_][A-Za-z0-9_]*[[:space:]]*\.
eval[[:space:]]*(/\*[^*]*\*/[[:space:]]*)+\(
assert[[:space:]]*(/\*[^*]*\*/[[:space:]]*)+\(
eval[[:space:]]*\([[:space:]]*\$[A-Za-z_][A-Za-z0-9_]*[[:space:]]*\)
assert[[:space:]]*\([[:space:]]*\$[A-Za-z_][A-Za-z0-9_]*[[:space:]]*\)
(call_user_func|call_user_func_array|system|exec|passthru|shell_exec|popen|proc_open)[[:space:]]*\([[:space:]]*(base64_decode|gzinflate|gzuncompress|gzdecode|str_rot13|rawurldecode|hex2bin|convert_uudecode)
(include|require|include_once|require_once)[[:space:]]*\(?[[:space:]]*['"]?(php://input|data://|http://|https://|ftp://)
file_get_contents[[:space:]]*\([[:space:]]*['"]php://input['"]
unserialize[[:space:]]*\([[:space:]]*\$_(GET|POST|REQUEST|COOKIE|SERVER|FILES)
EOF
# Medium-risk PHP patterns; more false positives
cat > "$REPORT_DIR/medium.ere" <<'EOF'
@?eval[[:space:]]*\(
@?assert[[:space:]]*\(
base64_decode[[:space:]]*\(
gzinflate[[:space:]]*\(
gzuncompress[[:space:]]*\(
gzdecode[[:space:]]*\(
str_rot13[[:space:]]*\(
rawurldecode[[:space:]]*\(
hex2bin[[:space:]]*\(
convert_uudecode[[:space:]]*\(
chr\([0-9]+\)[[:space:]]*\.[[:space:]]*chr\([0-9]+\)
\\x[0-9a-fA-F]{2}\\x[0-9a-fA-F]{2}
(move_uploaded_file|file_put_contents|fwrite|fputs)[[:space:]]*\(.*\$_(GET|POST|REQUEST|COOKIE|FILES)
(curl_exec|curl_multi_exec|fsockopen|pfsockopen)[[:space:]]*\(
array_map[[:space:]]*\([[:space:]]*\$[A-Za-z_][A-Za-z0-9_]*[[:space:]]*,
array_filter[[:space:]]*\([[:space:]]*\$[A-Za-z_][A-Za-z0-9_]*[[:space:]]*,
usort[[:space:]]*\([[:space:]]*\$[A-Za-z_][A-Za-z0-9_]*[[:space:]]*,[[:space:]]*\$
call_user_func(_array)?[[:space:]]*\([[:space:]]*\$
\$\$[A-Za-z_][A-Za-z0-9_]*
EOF
# Suspicious .htaccess / php.ini / .user.ini patterns
cat > "$REPORT_DIR/htaccess.ere" <<'EOF'
php_value[[:space:]]+(auto_prepend_file|auto_append_file|include_path)
php_admin_value[[:space:]]+(auto_prepend_file|auto_append_file|include_path)
auto_prepend_file[[:space:]]*=
auto_append_file[[:space:]]*=
SetHandler[[:space:]]+application/x-httpd-php
AddHandler[[:space:]]+application/x-httpd-php
AddType[[:space:]]+application/x-httpd-php
RewriteCond[[:space:]]+.*HTTP_USER_AGENT
RewriteCond[[:space:]]+.*HTTP_REFERER
RewriteRule[[:space:]]+.*https?://
Options[[:space:]]+.*ExecCGI
EOF
PHP_INCLUDES=(
--include='*.php' --include='*.php3' --include='*.php4' --include='*.php5' --include='*.php7'
--include='*.phtml' --include='*.phar' --include='*.inc' --include='*.module' --include='*.engine'
--include='*.theme' --include='*.php.bak' --include='*.php.old' --include='*.php.orig'
--include='*.php.save' --include='*.php.suspected' --include='*.php.txt' --include='*.ico.php'
)
CONFIG_INCLUDES=(
--include='.htaccess' --include='.user.ini' --include='php.ini' --include='*.ini'
)
HAS_WP=0
if command -v wp >/dev/null 2>&1; then
HAS_WP=1
fi
log "WP-CLI available: $([ "$HAS_WP" -eq 1 ] && echo yes || echo no)"
while IFS= read -r site; do
[ -d "$site" ] || continue
log "--- Scanning $site"
# High-risk PHP patterns
grep -RIniE -f "$REPORT_DIR/high.ere" "${PHP_INCLUDES[@]}" "$site" 2>/dev/null >> "$HIGH" || true
# Medium-risk PHP patterns
grep -RIniE -f "$REPORT_DIR/medium.ere" "${PHP_INCLUDES[@]}" "$site" 2>/dev/null >> "$MEDIUM" || true
# Targeted search for CO/OK/IE style obfuscation with eval-like functions.
# This is heuristic and may be slow on large sites.
grep -RIliE 'eval|assert|base64_decode|gzinflate|gzuncompress|gzdecode|str_rot13|create_function|call_user_func' \
"${PHP_INCLUDES[@]}" "$site" 2>/dev/null | while IFS= read -r f; do
if grep -qE "['\"]CO['\"]" "$f" 2>/dev/null \
&& grep -qE "['\"]OK['\"]" "$f" 2>/dev/null \
&& grep -qE "['\"]IE['\"]" "$f" 2>/dev/null; then
echo "$f" >> "$COOKIE_SHELL"
fi
done
# PHP/executable files inside uploads
find "$site" -type f \( \
-ipath '*/uploads/*' -o -ipath '*/upload/*' \
\) \( \
-iname '*.php' -o -iname '*.php3' -o -iname '*.php4' -o -iname '*.php5' -o -iname '*.php7' \
-o -iname '*.phtml' -o -iname '*.phar' -o -iname '*.cgi' -o -iname '*.pl' -o -iname '*.py' \
-o -iname '*.sh' -o -iname '*.asp' -o -iname '*.aspx' -o -iname '*.jsp' \
\) -print 2>/dev/null >> "$SUSPECT_PATHS"
# Known suspicious filenames and backups
find "$site" -type f \( \
-iname 'wp-vcd.php' -o -iname 'wp-tmp.php' -o -iname 'wp-feed.php' -o -iname 'wp-log.php' \
-o -iname 'wp-confg.php' -o -iname 'classwithtoconstructor.php' -o -iname 'admin.php.bak' \
-o -iname 'wso.php' -o -iname 'c99.php' -o -iname 'r57.php' -o -iname 'b374k.php' \
-o -iname 'alfa.php' -o -iname 'xleet.php' -o -iname 'shell.php' -o -iname 'cmd.php' \
-o -iname 'mini.php' -o -iname 'up.php' -o -iname 'uploader.php' \
-o -iname '*.php.suspected' -o -iname '*.php.bak' -o -iname '*.php.old' -o -iname '*.php.orig' \
-o -iname '*.php.save' -o -iname '*.php.swp' -o -iname '*.php~' -o -iname '.*.php' \
\) -print 2>/dev/null >> "$SUSPECT_PATHS"
# World-writable PHP files are dangerous
find "$site" -type f \( \
-iname '*.php' -o -iname '*.php3' -o -iname '*.php4' -o -iname '*.php5' -o -iname '*.php7' \
-o -iname '*.phtml' -o -iname '*.phar' -o -iname '*.inc' \
\) -perm -o+w -print 2>/dev/null >> "$SUSPECT_PATHS"
# Recently modified files; 14 days. Adjust if needed.
find "$site" -type f \( \
-iname '*.php' -o -iname '*.php3' -o -iname '*.php4' -o -iname '*.php5' -o -iname '*.php7' \
-o -iname '*.phtml' -o -iname '*.phar' -o -iname '*.inc' -o -iname '.htaccess' -o -iname '.user.ini' \
\) -mtime -14 -print 2>/dev/null >> "$RECENT"
# .htaccess / ini suspicious settings
grep -RIniE -f "$REPORT_DIR/htaccess.ere" "${CONFIG_INCLUDES[@]}" "$site" 2>/dev/null >> "$HTACCESS" || true
# WP-CLI integrity checks if available
if [ "$HAS_WP" -eq 1 ]; then
{
echo "=== WP-CLI: $site ==="
wp core verify-checksums --path="$site" --allow-root 2>&1 || true
wp plugin verify-checksums --all --path="$site" --allow-root 2>&1 || true
wp theme verify-checksums --all --path="$site" --allow-root 2>&1 || true
echo "--- Administrators"
wp user list --role=administrator --fields=ID,user_login,user_email,user_registered \
--path="$site" --allow-root 2>&1 || true
echo "--- All users with roles, first 200 lines"
wp user list --fields=ID,user_login,user_email,roles \
--path="$site" --allow-root 2>&1 | head -n 200 || true
echo "--- Super admins, if multisite"
wp super-admin list --path="$site" --allow-root 2>&1 || true
echo "--- Active plugins"
wp option get active_plugins --path="$site" --allow-root 2>&1 || true
echo "--- siteurl/home"
wp option get siteurl --path="$site" --allow-root 2>&1 || true
wp option get home --path="$site" --allow-root 2>&1 || true
echo "--- Cron events"
wp cron event list --path="$site" --allow-root 2>&1 || true
echo
} >> "$WPCLI"
fi
done < "$WP_LIST"
# Deduplicate some reports
for f in "$HIGH" "$MEDIUM" "$COOKIE_SHELL" "$SUSPECT_PATHS" "$RECENT" "$HTACCESS"; do
if [ -s "$f" ]; then
sort -u "$f" -o "$f"
fi
done
log ""
log "=== Results summary ==="
for f in "$HIGH" "$COOKIE_SHELL" "$MEDIUM" "$SUSPECT_PATHS" "$RECENT" "$HTACCESS" "$WPCLI"; do
if [ -f "$f" ]; then
lines=$(wc -l < "$f" 2>/dev/null || echo 0)
log "$(basename "$f"): $lines lines"
fi
done
log ""
log "Next steps:"
log "1. Review $HIGH and $COOKIE_SHELL first."
log "2. Do not delete automatically."
log "3. If WP-CLI was available, review $WPCLI for failed checksums and unknown admins."
log "Done."