to confirm the agent is * actually prepended and running. We answer and exit BEFORE any WAF logic so * the check is cheap and can't be blocked by the agent's own rules. * The token is required so this endpoint can't be used to fingerprint the site. * ──────────────────────────────────────────────────────────────────────── */ if (isset($_GET['__wordfort_health'])) { $tokenFile = __DIR__ . '/.wordfort-health-token'; $expected = @file_get_contents($tokenFile); $given = $_GET['__wordfort_health']; if ($expected !== false && hash_equals(trim($expected), (string)$given)) { header('Content-Type: application/json'); header('X-WordFort: active'); echo json_encode([ 'wordfort' => 'active', 'version' => WORDFORT_VERSION, 'php' => PHP_VERSION, 'ts' => time(), ]); exit; } // Wrong/again missing token — say nothing useful, just a plain 404-ish. http_response_code(404); exit; } /* ────────────────────────────────────────────────────────────────────────── * MAIN INSPECTION * ──────────────────────────────────────────────────────────────────────── */ wordfort_inspect(); function wordfort_inspect() { $ip = wordfort_real_ip(); $method = $_SERVER['REQUEST_METHOD'] ?? 'GET'; $uri = $_SERVER['REQUEST_URI'] ?? '/'; $ua = $_SERVER['HTTP_USER_AGENT'] ?? ''; $qs = $_SERVER['QUERY_STRING'] ?? ''; $body = @file_get_contents('php://input') ?: ''; $path = strtok($uri, '?'); $payload = $qs . ' ' . $body; // Verified search crawlers bypass ALL blocking (protects SEO). if (wordfort_is_verified_crawler($ip, $ua)) return; $reason = null; $reason = $reason ?? wordfort_check_probe($path); $reason = $reason ?? wordfort_check_ua($ua); $reason = $reason ?? wordfort_check_method($method); $reason = $reason ?? wordfort_check_traversal($uri); $reason = $reason ?? wordfort_check_sqli($payload); $reason = $reason ?? wordfort_check_xss($payload); $reason = $reason ?? wordfort_check_injection($payload); if ($reason) { wordfort_block($ip, $uri, $ua, $reason); } } /* ── Detection: scanner probes ─────────────────────────────────────────── */ function wordfort_check_probe($path) { $probes = [ '/wp-login.php','/wp-config.php','/xmlrpc.php','/wp-includes/', '/wp-content/debug.log','/wp-admin/install.php', '/.env','/.git/config','/.git/HEAD','/.htpasswd','/.htaccess', '/web.config','/composer.json','/package.json','/.npmrc', '/backup.sql','/dump.sql','/db.sql','/database.sql','/.bash_history', '/phpinfo.php','/info.php','/test.php','/php.php', '/shell.php','/c99.php','/r57.php','/cmd.php','/webshell.php','/eval.php', '/config.php.bak','/settings.php.bak','/wp-config.php.bak', '/administrator/','/phpmyadmin/','/pma/','/adminer.php','/cpanel', '/.aws/credentials','/.ssh/id_rsa','/server-status','/server-info', ]; foreach ($probes as $p) { if (stripos($path, $p) !== false) return 'probe:' . $p; } return null; } /* ── Detection: bad user-agents ────────────────────────────────────────── */ function wordfort_check_ua($ua) { if ($ua === '') return 'ua:empty'; $bad = [ 'sqlmap','nikto','nessus','masscan','dirbuster','gobuster', 'wfuzz','hydra','acunetix','nmap','zgrab','openvas', 'libwww-perl','python-urllib','jaeles','httpx','nuclei', ]; $l = strtolower($ua); foreach ($bad as $b) { if (strpos($l, $b) !== false) return 'bad_ua:' . $b; } return null; } /* ── Detection: HTTP method ────────────────────────────────────────────── */ function wordfort_check_method($method) { $allowed = ['GET','POST','HEAD','OPTIONS']; if (!in_array(strtoupper($method), $allowed, true)) { return 'method:' . substr($method, 0, 20); } return null; } /* ── Detection: path traversal ─────────────────────────────────────────── */ function wordfort_check_traversal($uri) { $patterns = [ '#\.\./#','#\.\.%2f#i','#%2e%2e#i','#\.\.\\\\#', '#/etc/passwd#i','#/etc/shadow#i','#/proc/self/#i','#%00#', '#php://#i','#file://#i','#data://#i','#zip://#i', ]; foreach ($patterns as $p) { if (preg_match($p, $uri)) return 'traversal'; } return null; } /* ── Detection: SQL injection ──────────────────────────────────────────── */ function wordfort_check_sqli($input) { $patterns = [ '#union[\s/*]+select#i','#select.+from.+information_schema#i', '#insert\s+into#i','#drop\s+table#i','#update.+set.+=#i', '#\bor\b\s+\d+\s*=\s*\d+#i','#\band\b\s+\d+\s*=\s*\d+#i', '#sleep\(\s*\d+\s*\)#i','#waitfor\s+delay#i','#benchmark\s*\(#i', '#xp_cmdshell#i','#exec(\s|\+)+(s|x)p#i','#cast\s*\(.+as#i', "#'\s*or\s*'#i","#'\s*=\s*'#i",'#--[\s]#','#/\*.*\*/#', ]; foreach ($patterns as $p) { if (preg_match($p, $input)) return 'sqli'; } return null; } /* ── Detection: XSS ────────────────────────────────────────────────────── */ function wordfort_check_xss($input) { $patterns = [ '#]#i','#javascript:#i','#vbscript:#i', '#on(load|error|click|mouseover|focus|blur|key|submit)\s*=#i', '#403 Forbidden' . '' . '' . '

403

' . '

Your request was blocked.

' . '

Protected by ' . 'WordFort

' . ''; exit; } /* ── Async report to collector (non-blocking, 1s cap) ──────────────────── */ function wordfort_report($ip, $uri, $ua, $reason) { if (!function_exists('curl_init')) return; $ch = curl_init(WORDFORT_ENDPOINT); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_POSTFIELDS => json_encode([ 'key' => WORDFORT_KEY, 'ip' => $ip, 'uri' => substr($uri, 0, 500), 'ua' => substr($ua, 0, 300), 'reason' => $reason, 'method' => $_SERVER['REQUEST_METHOD'] ?? '', 'host' => $_SERVER['HTTP_HOST'] ?? '', 'ts' => time(), 'v' => WORDFORT_VERSION, ]), CURLOPT_HTTPHEADER => ['Content-Type: application/json'], CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 1, CURLOPT_CONNECTTIMEOUT => 1, ]); @curl_exec($ch); @curl_close($ch); } /* ── Resolve the real client IP ────────────────────────────────────────── */ function wordfort_real_ip() { foreach ([ 'HTTP_CF_CONNECTING_IP', 'HTTP_X_REAL_IP', 'HTTP_X_FORWARDED_FOR', 'REMOTE_ADDR', ] as $k) { if (!empty($_SERVER[$k])) { return trim(explode(',', $_SERVER[$k])[0]); } } return '0.0.0.0'; }