## PortSwigger - Web Security
### 1. SQL injection
> I skip UNION attack there as i feel it's a little bit easy to exploit so let's begin with the other one right now.
#### Blind SQL injection with conditional responses
- First of all, blind injection is a kind of injection where we don't have any return values , all we know is the "signal" string: "Welcome back" in the page.
- As we don't have any return values to leak information, we must base on the cookie value. Particularly, the presence of the signal string strongly depends on the cookie header:

- Hence, we need to take advantage of this part. Since we only know the signal string, we can try some techniques like: leaking the length of password. Eventually, we can brute-force the password one character at a time for each position.
- Check password length:

- Way 1: using Intruder:
- First, we set up the payload with brute-force type, then we can infer the correct response by the unique response size it gives:

- Confirm this:

- Okay, it's just a single payload for now. To speed things up, we can automate it by using two payload positions: the current character and the current position .
- Way 2: from there we can ask AI to generate for us python to craft a brute-force script manually. As we can keep track of the moment we found a correct character for current position, we can stop trying for this position and focus on the next one, this makes custom py script noticeably faster.

#### Blind SQL injection with conditional errors
- First, I check whether injection is feasible or not:


- Now I will identify the database type by using concat function.

- Basically, concat function with 1 parameter is only available in Mysql. Now, let's try another query:

- But if we specify a table name:

- Hola, now we can confirm that the database being used is Oracle and the query is processed by the back-end as well!
- Looking at the cheat-sheet:

- Whenever our condition is true, it will execute TO_CHAR(1/0), which triggers division-by-zero error. This results in an external server error. From there, we can process our brute-force strategy based on the status it responses.
- First fuzzing the length of password:

- Let's make a practice using Intruder to find the first character of the password.

- Ok, it's "r", the rest is just about waiting for the result of brute-force process...

#### Visible error-based SQL injection

- It gives a 200 status, let's fuzz more:

- It still returns a 200 status and everything appears normal, so the result of the query likely does not affect the application's output. Let's try more:

- This payload works! but...

....
- I have tried a lot and generally i just get the error shown in the pic above, it's "Expected char"... but when we delete the TrackingId value and make the payload shorter, it changes to:

- and:

- This might highly suggest of a hypothesis that the input field has length limit.
- Now, we can consider that we have a limit space for our payload to have a good return status. Otherwise, we will get an 500 error. There's an idea is to check a condition that if it's true, a specific status is always returned, similarly apply it to the opposite condition as well... But how?
- After examining, I have no ideas on how to proceed. Running our of interesting ideas, I decided to read the solution. There, I learned that intentionally casting the text type into int may cause an error revealing that the value actually a string and obviously we can observe by the response. Let's try ourselves.

- Yeh, it leaks that the first row in the users table is of administrator. Now, everything else is really easy!

#### Blind SQL injection with time delays
- This lab always returns a 200 status eventhough i request like this:

- In this lab, we must exploit the blind SQLi vulnerability to cause a 10 second delay.

- Just make it like a real exploit to achieve administrator password. Lab solved!
#### Blind SQL injection with time delays and information retrieval
- As in the previous lab I could craft my own script to take advantage of time delays, so now everything has become an easy task.

- To make the results more convincing, I will use Intruder to check the first character of the password.

- I was too impatient to wait for the response so I just made the page sleep for only 3 seconds if the condition is true. There, I found out that there is exactly only one request with a noticeably response size. I tried it by Repeater to see whether it's a sign indicating that it's the correct character for the first position or not. And luckily:

- The wait was so long. Everything seems to be on the right track, let's craft our final script to achieve the password.

- Lab solved!
#### Blind SQL injection with out-of-band interaction and Blind SQL injection with out-of-band data exfiltration
> The 2 out-of-band SQLi labs require either a DNS server or the professional version of Burp Suite, so I decided to just read about the technique and skip to the last one.
#### SQL injection with filter bypass via XML encoding
- There filter category is no longer available in this lab, but there's something interesting in this route:

- The "/product/stock" endpoints accepts requests with an XML-formatted, which may be leveraged for futher exploit.

- As we can see, the application is implemented to filter or sanitize potentially malicious characters, so we will obfuscate them to make it harder to detect.

- At first, I attempted a simple injection with XML-encoded format for both productId or storeId, but eventually both were detected as attacks. I use Hackvertor Extension to encode as the lab recommend it.

- From there, We can easily change the value it casts into a "select case when..then..else..end". By observing the number of units it returned, we can easily bruteforce the entire password. Comfirming by guessing the length of password:

- 921 units

- 17 units. This confirms our assumption was correct! From there we can efficiently brute-force one character of password at a time for given position.
- Observing the response, it strongly suggests that the number of returned columns is only one. Let's try to use a UNION attack.

- Nicee, Lab solved!
### 2. Cross-site scripting (XSS)
#### Reflected XSS into HTML context with nothing encoded

- We can assume that the back-end will perform something like "X search results for {user input}". Hence, if our input is not sanitized, we can execute our JavaScript which leads to a XSS vul. From there we just need to perform: "<script>alert(1)</script>".
#### Stored XSS into HTML context with nothing encoded
- We will inject our payload into comment, this comment will be stored in the database and when other users view this comment, the payload will automatically execute.
#### DOM XSS in document.write sink using source location.search

- From there, we can inject something like this:

#### DOM XSS in innerHTML sink using source location.search
- I found this script

- The application accepts our input without any sanitization or filtering. Since this is still a basic DOM XSS vulnerability, I will use an svg tag to solve this lab.
#### DOM XSS in jQuery anchor href attribute sink using location.search source

- window.location.search retrieves the query string, then URLSearchParams will parse this string into key-value pairs, .get('returnPath') will get value associated with the 'returnPath' key.
- Let's inject directly to our URL:

- Lab solved.
### 3. API testing
#### Exploiting an API endpoint using documentation
- When I update my email, there is a request like this:

- What if I change "PATCH" to "GET"? let's see.

- It returned successfully with a 200 status code. Let's try other routes.


- Wait, the status code 302 means that the resource was found but the content-length is still 0 which suggests that it has been redirected elsewhere. Use our browser to see what happens.

- Then we know what to do next! let's just test something j4fun =))


- An interesting beginning! Lab solved.
#### Exploiting server-side parameter pollution in a query string
- When I sent a POST request to the endpoint /forgot-password with username = administrator, the response revealed a hidden email address.

- Additionally, I noticed there is another suspicious endpoint, but I still don't figure out anything too useful there.

- When I made a POST request to the /forgot-password endpoint with an additional, random parameter: x=3, it responded with an error message:

- This strongly suggests that the application treated "x=3" as a separate parameter. This is because the application functions correctly with only username = administrator, but when we added another parameter using URL-encode "&" seperator, an error occured.
- We know that "#" character acts as fragment marker in URLs. Based on it, we can test its behaviors. The idea is that the server will receive our request, use our input to build another request to an internal API or build another url for backend HTTP request.

- It looks like we need a "Fied" parameter.

- Okay, we have to accept the fact that it's impossible to guess the actual value in this case. Therefore we will use Intruder to bruteforce the server-side variable name to assign to the field. As I don't have a professional version of Burp so I will craft my own python script:
```python!
import requests
url = "https://0af3001a03d922ef8157077000a900c9.web-security-academy.net/forgot-password"
cookies = {
"session": "840Ob0DdtacOcL95jz2vzVPk3uHsOdDc"
}
headers = {
"Content-Type": "application/x-www-form-urlencoded"
}
with open("server_side_variable_name.txt") as f:
for line in f:
field_name = line.strip()
payload = f"csrf=oQTAcSBKPhbkERTEA6uKng1z6xHvuywQ&username=administrator%26field={field_name}%23"
r = requests.post(url, data=payload, cookies=cookies, headers=headers)
if r.status_code != 400:
print(f"[+] Possible match: {field_name} - Status: {r.status_code}")
```

- Try email first:

- Try username:

- At that point, it seems like the application will accept any variable as long as it's a valid one and return its value to us ... we remember that there is a js code at /static/js/forgotPassword.js, we can see there's a parameter at this:

- Let's use that parameter then:


- Lab solved.
### 4. Authentication
#### Username enumeration via different responses
- Okay, coming to this first lab of this module, we are given a password and a username list. Our iead is just to brute-force all the possible combinations of them, but at first glance we notice that if we try a random username and password then it responsed:

- So we have an idea is that instead of try all combination of username and password, we just try all username with a fix password first with a wish to receive something like "invalid password" instead of "invalid username".

- Well, among a lot of username i tried, there is exactly one distinguish with other.

- Yeah! It's invalid password. Then we will try the password list with this username, so in generall instead of try all n * m combinations, we just try n + m -> The time complexibility is decreased so much and the problem turns to really feasible.

- Lab solved!

#### Simple bypass 2FA
- This lab gives us 2 credentials: one for us and one for carlos, our target is to log in account carlos without knowing his 2MFA code.
- After logging successfully, it requires us to give it the 2MFA code, at there we just change the url to another endpoint which is valid and boom we are now in carlos account without entering any 2MFA code. I think this flaw happened due to not changing the session cookies, the session cookie for submitting 2MFA code successfully should have the full authorization of that user, but in this lab, the first session cookie is enough to do everything. In fact, we have to rotate session cookie and carefully provide what kind of permission when the user log in successfully without using 2MFA.

- Lab solved!

#### Password reset broken logic
- After logging in with my credential, look at this:

- This information accidentally leaks that all user email address. Okay, i'll attempt to change my password to carlos@exploit-0ac0009f0396cd5080070708017f00b9.exploit-server.net, then i will choose forget password and expect there is a reset passsword email sent back to my new email address

- After trying 2 times, i still can not make the server sends the reset password url correctly back to me, although the email address we see is still carlos, eventually i just change my account password myself.
- Looking closer to the request when submitting a new password

- There is a hidden input and ... it's our username, i think it takes this parameter from the previous section: "Enter your email or your username". From there, i think all we need is to generate a new temp-forgot-password-token and change the username to our target: "carlos".

- Lab solved!

#### Username enumeration via subtly different responses
- Generally, this lab is the same with the first lab in this module, but instead of announcing that the username is invalid, it tells us that "invalid username or password" -> this makes the work harder!
- I try grep&&extract "Invalid username or password" and attack, this is what i found:

- Among so many similar responses, there is exactly one standing out, then i try to bruteforce password with this username


- Lab solved!

#### Username enumeration via response timing
- Okay there are 2 important things when it comes to this challenge
- First: the server blocks our ip if we try the wrong password multiple times. To bypass this we add another header called :"X-Forwarded-For". (this header is often used in proxy server, load balancer).
- Second: when we try to bruteforce, we are all know that we have to base on the response time to figure out what is the most highly response having the correct username. However, if we leave our password short, it won't work. We have to create a long enough password so that the time is completed differently between a "good" and a "bad" response.
- In this lab, we use Pitchfork (a kind of attack that use multiple payload and the intruder will iterate each set in parallel). I use 0-100 for "X-Forwarded-For" and a given list of username.

- Oke, "arizona" is the best candidate. The next bruteforce is for password.

-> password: 159753

- Lab solved!

#### Broken brute-force protection, IP block
### 5. Clickjacking
#### Exploiting clickjacking vulnerability to trigger DOM-based XSS
- I decided to try fill the feedback form and this is what i had:

- So it reflected my input name, try something else to test the script execution on that page:

- I've used **</image src=0 onerror=alert(1)>** and in fact it've executed! This hints us that we can do something like overlaying/clickjacking on this website.

- After some time, adjusting the div element now i have the correct place of the "fake" button. Let's make everything background invisible or something else but i don't have too much time to decorate it!


- Lab solved!

### 6. Deserialization
#### Modifying serialized objects
- When logged in successfully, looking at the response:

- We have a new session cookie and it's in a URL-encoded form as it contains percent-escapes like %3d. After decoding it by url-decoder and base64. Finally, in fact, the cookie is a serialized PHP object:

- So it represents something like this in php code:
**class User {
public $username = "wiener";
public $admin = false;
}**
-> Change the admin attribute to True

- Okay, let's edit the cookie and change our url to admin!

- Delete carlos now!

- Lab solved

### 7. SSTI (server-side-template-injection)
#### Basic server-side template injection
- Okay, we are hinted that "This lab is vulnerable to server-side template injection due to the unsafe construction of an ERB template.", so let's try it directly:

- As our message shows exactly on the response of the server, this strongly indicates that the server render our message directly. Try another:

- Our hypothesis was correct!

- Delete the target file!


- Lab solved!

### 8. Http request smuggling
#### HTTP request smuggling, confirming a CL.TE vulnerability via differential responses
- Okay, this is an innteresting technique. To make a http request smuggling, we have to pay attention to 2 kinda headers: Content-Length and Transfer-Encoding. A chunk's structure is something like this:
Size (Hex)
CRLF
Data
CRLF
- And the Terminating Chunk is:
0
CRLF
Optional Trailers
CRLF
- So the idea here is that i will add 2 headers together in a request so that i can make the server confused between choosing which kind of rule to process. However, if 2 headers content-length and transfer-encoding, the server will choose the transfer-encoding.
- Yeb, we will craft the content length longer than the terminated chunk like this:

- The request is still successfully, as the server reads the terminated chunk normally. Having said that, the real problem comes when the server serves the next request, our extra data after terminated chunk will be some first bytes of the next request, hence the next request will be something like GET /404...
-> Not found!

- Lab solved!


### 9. Path traversal
#### File path traversal, simple case

- Lab solved!
#### File path traversal, traversal sequences blocked with absolute path bypass

- Like its name, lab solved!
#### File path traversal, traversal sequences stripped non-recursively
- Okay so, developers might remove "../" as they know it could open a door for path traversal.
- I will bypass this using 4 dots and 2 forward slashs (Hackmd could not let me type it correctly there) so when it removes, it'll lead to our target one.

- Lab solved!
#### File path traversal, traversal sequences stripped with superfluous URL-decode
- Actually, I guessed that to solve this lab I have to perform URL encoding twice but I dont know why I encode /etc/passwd twice it did not work, when I changed to encode "../../../../" twice, it worked?!?

- Lab solved!

#### File path traversal, validation of start of path
- Based on the description of the lab, we should remain the prefix of the path.

- Lab solved!
#### File path traversal, validation of file extension with null byte bypass
- To solve this lab we will trick the server to think that the file extention we try to request is ".jpg" by adding the null byte between the file name and the extention. The null byte likely cut off the extention when the server try to take it for the user.

- Lab solved!
### 10. Cross-origin resource sharing (CORS)
- Okay, before start the first lab of this module, i wanna note out something:
- CORS and CSRF share some similarities but still are not the same though, with CORS vul, attacker can fetch and see the server's response but with CSRF attacker does not know the response of the server -> CORS is kind of data theft, whilst CSRF is about unauthorized action.
- To prevent CORS, we should consider to use a whitelist of trusted origins and for some sensitives endpoints or APIs then never let it accessible from cross-origin (if it is not really necessary).
#### CORS vulnerability with basic origin reflection

- Look at this response: it has a header like: Access-Control-Allow-Credentials: True, but that's we send that request from the same origin, if we want to ensure that this website has a CORS vulnerability we have to try a random origin to see what happen with that header value.

- This confirms that we exploit this server based on a CORS misconfiguration.

- Then we watch the log:


-> Lab solved
### 11. File upload vulnerabilities
#### Remote code execution via web shell upload
- Okay this is another interesting topic, for this lab, we have to create a php file -> upload it -> rcm. As the server does not explicitly check the type of the file we upload so we can easily achieve our target.

- Read /home/carlos/secret

- Lab solved!

#### Web shell upload via Content-Type restriction bypass
- This time with the previous trick does not work anymore. It might check our file's extension?

- However, when looked at the request packet:

- It has a additional field for the content type which is currently text/php. Let me try change it to image/png:

- Read the secret!

- Lab solved!

#### Web shell upload via path traversal
- Let's escape the "/" by using its encoded form: %2f. We can see the response from the server:


- Let's read the secret!

- Lab solved!

#### Web shell upload via extension blacklist bypass
- This time, it uses the blacklist for file extension, let me try the old trick:

- Okay, it's already smarter than the last time, we have to move on another way.

- This hints so much, it just checks the extension directly! Let's config a rule for the directory!

- Now, uploading our web_shell with jpg extension!



- Lab solved!

#### Web shell upload via obfuscated file extension
- I added a null byte before the extension:

- Let's see what is our avatar right now:

- Lab solved!

### 12. Command Injectio
#### OS command injection, simple case
- At here both "|" and ";" works well


- Lab solved!

#### Blind OS command injection with time delays
- Okay, make it sleep 10 seconds, but have to find a correct place to put it in, then encode it as well.

- Lab solved

#### Blind OS command injection with output redirection
- I tried to create a file named flag.txt in /var/www/images/ first but it said:

- Let me try something else:

- Okay, it seems like we have to creae the file first. After that let's check whether we could write and get something there.


- Okay, lab solved!
