In the previous post, we discussed what security is, the methodologies applied to attack applications, and who determines the requirements and laws that we must abide by.
In this post, we focus on the practical part of security, starting from the OWASP top 10 vulnerabilities list, part of every official external penetration-test that companies must go through before getting certified.
But first, we need to discuss what is OWASP and what role they play in the world of application security?
The Open Web Application Security Project
OWASP is a nonprofit foundation that assists the community in improving software-security in web applications by providing:
- Open source tools
- Community and Networking
- Education and training materials
When it comes to security, OWASP is a great source to follow, and they are a leading foundation for setting up a global standard in the industry.
OWASP TOP 10
Our main focus on this post is the foundation’s most important project, the top 10 list, which provides us with the most critical vulnerabilities in software development as of today (2020); it consists of the following vulnerabilities:
- Injections
- Broken Authentication
- Sensitive Data-Exposure
- XML external entities
- Broken Access Control
- Security Misconfiguration
- Cross-Site-Scripting
- Insecure-Deserialization
- Using Components with Known Vulnerabilities
- Insufficient Logging and Monitoring
The list is considered imperative knowledge to any web developer, and it is also part of the requirements for getting certified.
In this post, we will focus on Injections and broken authentications, but before we start explaining these vulnerabilities, let us first set up a vulnerable application, which will help us learn them first-hand.
OWASP Juice Shop
Juice-Shop is a vulnerable application developed by the OWASP Foundation for security-training in software companies. This application has everything you don’t want in your product, yet it has everything you need for training sessions.
Juice Shop – Docker Installation
Installation is quite simple on docker. Just run the following command
docker run –rm -p 3000:3000 bkimminich/juice-shop
and then open localhost:3000 on your browser.
Juice Shop – Links
- Juice Shop Github (if you prefer not to use docker, in the main GitHub page, they provide you with other ways)
- Challenges
- Solutions
Rocco (Our Attacker)
Injections
The first common attack that Rocco can use is a query injection.
Let’s say that Rocco has done some research and found out that we are using SQLLITE for our juice shop, so he went on google and searched for common injections in SQL code.
Rocco is a smart guy, so he thought, what’s the most common query for logins, well.
“select * from users where email=’some_email’ and password = encrypt(some_password)
Rocco then read that double-dash comments out the rest of the SQL statement, so he figured out that the easiest way to hack would be:
- closing the email input with an apostrophe (‘)
- add a clause which is always true, like 1=1
- add a double dash to deactivate the rest of the SQL statement
Yes, it will work in this case, but if you think that it’s all, please visit
Solution
So how do we stop Rocco here?
PreparedStatements
Many database engines enable you to provide an ability to define a pre-compiled statement, a parameterized query template that is compiled and cached by the server engine.
Python Example:
We wish to search for a particular product and trigger the following query on MySQL DB.
“select * from catalog where name=?”
cnx = mysql.connector.connect(database='shop')
cursor = cnx.cursor(prepared=True)
stmt = "SELECT * FROM catalog WHERE name = %s"
cursor.execute(stmt, ("shampoo",))
for (name, price) in cursor:
print("{} = {}".format(name, price))
Since the name becomes a parameter for a precompiled query, the DB engine will only use it as expected.
There is no way to implant a MySQL clause because once the statement is precompiled, the driver sends just the parameters and not the entire query.
Stored Procedures
Defines a custom function on the database and sends it the parameters, same as in prepared-statement; this will cause the engine to use the input as a parameter and not as a complete query.
Mysql Example:
On Mysql, create fetch_product that runs our query with the provided name parameter:
CREATE PROCEDURE fetch_product(IN in_name CHAR(20))
BEGIN SELECT *
FROM catalog WHERE name = in_name ;
END
result_args = cursor.callproc('fetch_product', ['shampoo'])
Whitelists
PreparedStatement and StoredProcedure do not cover cases where the query’s dynamic attributes are not column values, such as table name and select columns; In these cases, you would need to use a Whitelist, as these are not supported in the previous solutions.
Whitelist refers to a list of valid inputs, and any input that is not in that list, or matches one of its regexes, will be considered invalid, and you should return a user error for it.
For example, in column names, a whitelist will consist of column names in the table you are querying.
Having said that, if a client-side input contains DB names and table names, that’s a different kind of security vulnerability; you are exposing the users to the internal details of your application, so you may want to modify your design.
One proper solution is to use UI names on the client-side that will be mapped to DB names on the backend; another way is to create a method for each columns’ projection.
Broken Authentication
As you may recall from the previous post, that’s the Active reconnaissance phase. The attacker manually interacts with the application to understand it’s weak spots.
Registration
That page alone consists of several critical issues:
Passwords
If you play around with the password field, you will notice that we do not enforce the user to set up a safe password.
One can choose his or her first name (if it consists of 5 letters) or a combination of first and last name.
You may say, well, but there is advice on setting up a proper password; if the user chooses not to do so, it’s not my problem.
No, it’s most definitely your problem; you must prevent your users from being harmed, even if it is at the cost of some level of usability.
- at least 8 characters
- consisting of at least one non-alphanumeric character (i.e., @$^&, etc.)
- contains both numbers and letters
- contains both upper and lower case letters
- does not contain the username, first and last name
If you force your users to follow these requirements, it will be challenging for automatic utilities to find the user’s password
- What you know (e.g., password)
- What you have (e.g., phone number, Facebook account)
- What you are (e.g., fingerprint)
One example, which many of us are familiar with, is multi-factor authentication for AWS accounts.
We login by providing a username+password, and then we are asked to provide a google-authenticator code.
I don’t want to focus too much on the implementation of specific solutions, but if you wish to integrate google authenticator into your application, this blog page covers all the required details
Before submitting the registration form, Rocco opened Google-Devtools(F12) to see whether we transfer this critical data safely to the server.
What is Man-In-The-Middle Attack(MIMD)
A man in the middle attack is when an attacker manages to control the transmission between 2 parties without knowing its presence.
An attacker can then eavesdrop on confidential messages, hijack sessions, and tamper with the data being sent.
We may cover examples of how an attacker can come between the user and the server in later posts, but for now, be aware that Rocco has it within its skillset.
Therefore, Rocco can eavesdrop on registration requests and use the user credentials as his own.
Broken Authentications mitigations:
- Use SSL encryption for all authentication-related requests :
- Remember Me
- Login
- Registration
- Enforce:
- Strong password
- Password renewals every several months
- Use multi-factor authentications
- All endpoints used for secure resources should authenticate the user.
- Write Audit logs for all activities related to authentication and authorization.
- Invalidate session-id once the user logs out
- Make sure that the application generates a random session id and keep it in a secure location.
- The session Id generated must be short-lived and become invalid after a specific timeout (a few hours is recommended)
Summary
In this post, you were exposed to the first two vulnerabilities in the OWASP top 10 list and how to mitigate them.
You also learned how to practice ethical hacking using the OWASP juice-shop, which is probably the most efficient security training tool, as nothing beats experiencing the various hacking methodologies when you wish to learn how to defend against them.
If you did not install it yet, I strongly recommend you do so and try the example I have given here, or even better, try also solving the other challenges: https://bkimminich.gitbooks.io/pwning-owasp-juice-shop/content/part2/injection.html
note that there are also solutions on the following page https://bkimminich.gitbooks.io/pwning-owasp-juice-shop/content/appendix/solutions.html
In the next posts, I will go over several more vulnerabilities and discuss them thoroughly, along with examples and guidelines and how to mitigate them.