If your nginx access log shows frequent requests for PHP files you don’t recognize, your server is likely being probed by bots or attackers scanning for vulnerable scripts. This guide shows you how to identify those attempts, trace their source, and decide whether to block them or dig deeper.
What You’ll Need
- SSH access to your server (or a way to read the nginx logs)
- Basic familiarity with the command line and grep
- Permission to read log files (usually root or a user in the adm group)
- Optional: a tool like
goaccessorjqfor analysis
Step-by-Step
- Locate your nginx access log. The default path is
/var/log/nginx/access.log, but it may be customized in your nginx config. Check withnginx -T 2>/dev/null | grep access_logor look in your site’s server block. - Filter for PHP requests. Run
grep '\.php' /var/log/nginx/access.log | tail -n 50to see the most recent attempts. This narrows the noise to requests that target PHP scripts. - Identify the suspicious patterns. Look for requests to files like
shell.php,cmd.php,wp-login.php, or paths like/uploads/,/images/, or/tmp/that shouldn’t contain PHP. Also watch for query strings withcmd=,exec=, or base64-encoded data. - Extract the source IPs. Use
grep '\.php' /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head -n 20to list the top IPs hitting PHP files. High counts from a single IP often indicate a scanner. - Check the user-agent strings. Run
grep '\.php' /var/log/nginx/access.log | awk -F'"' '{print $6}' | sort | uniq -c | sort -rn | headto see common user-agents. Bots often use generic ones likepython-requests,curl, or random strings. - Look at the response codes. A 404 means the file doesn’t exist; a 200 or 403 means it may have executed or been blocked. Filter for PHP requests with status 200:
grep '\.php' /var/log/nginx/access.log | grep ' 200 '— these are the most concerning. - Correlate with error logs. Check
/var/log/nginx/error.logfor related PHP errors or warnings. For example,grep 'PHP' /var/log/nginx/error.log | tailmay show attempts to include remote files. - Trace the IP origin. Use
whoisor an online lookup to see if the IP belongs to a cloud provider, a known scanner, or a random residential range. This helps you decide whether to block it. - Test if any file actually exists. If a request like
/wp-content/uploads/evil.phpreturns 200, check if that file exists on your server. Runfind /var/www -name 'evil.php'(adjust the path) to see if it was uploaded. - Decide on action. If the attempts are harmless (404s from scanners), you can ignore them or block the IPs. If a file exists or you see 200 responses, treat it as a potential compromise and investigate further.
Common Mistakes
- Ignoring 404s. A 404 doesn’t mean the attempt is harmless; attackers often probe for files that may exist later. Log them and monitor for repeats.
- Blocking IPs too aggressively. Some scanners come from shared hosting IPs or cloud providers that may also host legitimate visitors. Block only the specific IP if it’s clearly malicious.
- Forgetting about IPv6. Logs may contain IPv6 addresses; include them in your analysis and blocking rules.
- Not checking the actual file path. A request to
/shell.phpmight be rewritten by nginx to a different location. Always check therequest_uriand the actual file system. - Overlooking POST requests. Attackers often use POST to send payloads. Filter for both GET and POST:
grep -E 'POST|GET' log | grep '\.php'.
Tips
- Use
tail -f /var/log/nginx/access.logto watch attempts in real time while you work. - Set up logrotate to keep logs manageable; old logs can be compressed and archived for later analysis.
- Create a simple script that greps for common malicious patterns and emails you a daily summary.
- Use
fail2banto automatically block IPs that trigger certain rules, but test the rules first to avoid false positives. - If you use a CDN or proxy, remember that the IP in your logs may be the proxy’s IP, not the attacker’s. Check for the
X-Forwarded-Forheader.
Troubleshooting
No PHP requests appear in the log. Your access log may be in a different format or location. Check the nginx config for log_format and access_log directives. Also, if you use a reverse proxy, the log might be on the backend server.
Log file is huge. Use grep with a time filter, e.g., grep '30/Nov/2024' log or use zcat for rotated logs. Alternatively, use tail -n 1000 to limit the output.
Requests are encoded. Attackers often URL-encode paths. Decode with python3 -c "import urllib.parse; print(urllib.parse.unquote('...'))" or use jq -r '.request_uri' | python3 -c 'import sys,urllib.parse; print(urllib.parse.unquote(sys.stdin.read()))' if logs are in JSON.
You see a 200 for a PHP file that doesn’t exist. This could be due to a rewrite rule or a custom error page. Check the nginx config for try_files and location blocks that may route requests to a PHP handler.
Attempts come from many different IPs. This is typical of a distributed scan. Focus on the patterns rather than individual IPs, and consider blocking at the firewall level with a list of known scanner subnets.
Frequently Asked Questions
Q: What does a typical malicious PHP request look like?
A: Often something like GET /shell.php?cmd=whoami or POST /wp-content/plugins/revslider/revslider.php. The path is usually for a known vulnerable script or a generic name like c99.php.
Q: Should I block every IP that hits a PHP file?
A: No. Many legitimate requests, like to index.php, are normal. Only block IPs that repeatedly target suspicious files or show a clear scanning pattern.
Q: How can I tell if an attempt succeeded?
A: Look for a status code of 200 and a response size that isn’t zero. Also check if the requested file exists on your server. If it does, that’s a red flag.
Q: What if I find a suspicious PHP file on my server?
A: Do not open it in a browser. Move it to a quarantine directory, check its contents for malicious code, and review your server for other signs of compromise. Change all passwords and update your software.
Q: Can I use nginx to block these attempts?
A: Yes, you can add a location block to deny access to common malicious files, or use a module like ngx_http_access_module to deny specific IPs. However, this is reactive; a Web Application Firewall is more proactive.
Q: Why do I see so many attempts from the same IP range?
A: Attackers often use cloud services or compromised servers to scan. The IP range may belong to a hosting provider that is being abused. Blocking the entire range may be too broad; block the specific IPs.
Related
Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.
More cards in this drawer
- Evaluate Private Cloud AI Security Operations Platforms
- Access the DOM in Angular Safely
- Websites Create QR Code? How It Works
- Space Engineers Server Name & Description Setup
- Tongue Escape Events Schedule: Full Guide
- f/2.8 Telephoto Zoom: What to Consider