In the space of 5 years, the number of Denial of Service (DoS) attacks has almost doubled. The result is the paralysis of tens of millions of web platforms and the loss of thousands or even millions of euros by victim organisations.
Companies such as Amazon and GitHub have already been affected by this type of attack. One of the best-known attacks is MIRAI, which used a botnet of nearly 100,000 hijacked machines to make Dyn’s services unavailable in 2016.
The consequences of a denial of service can range from a simple slowdown of a platform to the total unavailability of an information system. And with service continuity being a vital issue, it is important to take account of and prevent this risk.
So what is a DoS attack, and how can you protect yourself against it? That’s what we’ll be looking at in the rest of this article. In particular, we will explain the differences between a denial of service (DoS) and a distributed denial of service (DDoS). We will also detail the different types of attack with a few concrete examples and explain the principles and methods of DoS tests during a penetration test.
What is a denial of service (DoS) attack?
A Denial of Service (DoS) attack is a computer attack designed to slow down or make unavailable a server or a resource in general.
The motives behind these attacks vary. In most cases, denial of service attacks are carried out with the aim of extorting money from the victim. However, attackers may also be motivated by ideological, political or personal convictions.
There are several ways for carrying out this type of attack, but first it is important to understand the difference between a DoS and a DDoS.
What is the difference between DoS and DDoS attacks?
The main difference between a DoS and a distributed denial of service (DDoS) is that in a DoS attack, the victim is attacked by a single system.
In a DDoS attack, on the other hand, the attacker uses a multitude of systems to attack the victim. Because the attack comes from several sources at once, DDoS is generally faster and harder to block than DoS, and it is difficult to trace its source.
Carrying out DDoS tests as part of a penetration test is of little use, as it will always be possible to bring down a service if you devote the necessary resources to it.
DoS tests, on the other hand, can identify vulnerabilities in configurations or applications. And in these cases, patches can be implemented. We’ll come back to this point later in the article.
What are the different types of DoS attack?
There are several ways of carrying out a denial of service. We can classify them into different categories. Please note that this list is not exhaustive!
Teardrop attacks
In a Teardrop attack, the attacker sends heavy packets fragmented into many pieces to the victim.
However, the attacker will have fragmented these packets abnormally, which will destabilise the target system when it tries to reassemble the fragments into packets. This attack therefore exploits the IP protocol.
SYN Flood attacks
A SYN Flood attack consists of sending several connection requests to a server but not responding when the server tries to contact us in return to complete the handshake between the server and the client (in this case the attacker).
Thus, unable to complete all the handshake requests initiated by the attacker, the server will be too busy to connect to other legitimate users. It will therefore be slowed down or even become inaccessible. This attack exploits the TCP protocol.
Volumetric attacks
The aim of a volumetric attack is to overload the victim’s bandwidth. An example of this would be an attack that exploits the ICMP protocol by sending a large number of ICMP “echo” requests to the victim.
As a result, the bandwidth will be overloaded by these requests and the network will only be able to let through a few legitimate requests, if any at all.
Application-layer attacks
Application layer attacks consist of exploiting certain protocols at layer 7 of the OSI model, such as the HTTP protocol.
This is the type of attack that we are used to using during web application penetration tests.
DoS testing guidelines during a penetration test
The success of a denial of service depends on the resources deployed by the attacker. However, some denial of service attacks can be limited or even definitively corrected. And it is this type of attack that we focus on during a penetration test.
Researching these precise cases of denial of service is of interest to our customers because, once corrected, it prevents a single attacker with a single machine, a few tools and little technical knowledge from succeeding in bringing down the system.
In the rest of this article, we’ll look at concrete examples of vulnerabilities exploited to carry out successful Dos attacks. But first, a few details about DoS tests. To carry out this type of test in the best possible conditions as part of a pentest, it is important to take several aspects into account:
In the rest of this article, we’ll look at concrete examples of vulnerabilities exploited to carry out successful Dos attacks. But first, a few details about DoS tests. To carry out this type of test in the best possible conditions as part of a pentest, it is important to take several aspects into account:
- If the pentest cannot be carried out on a test environment, it is possible to conduct DoS tests during a specific time slot when a limited number of users will be impacted if the application is unavailable.
- Communication between the pentesters and the client technical team must be as efficient as possible in order to be reactive in the event of an incident and thus limit the impact.
- Finally, if the pentesters realise that the DoS attack is rapidly slowing down the targeted service, there is no need to go any further at the risk of destabilising the system even further. The vulnerability has been identified, and the service will have been impacted for only a very short time.
Common vulnerabilities that can be exploited to carry out DoS attacks
Let’s stay within the context of web application pentesting, with DoS tests in the scope. As mentioned above, these tests are carried out at specific times so as not to impact our customers’ business.
Generally speaking, a DoS attack is the result of 3 vulnerabilities:
- Improper configuration of the web server
- Poor implementation of a feature
- A vulnerable component
For each vulnerability, different attacks can be used to achieve a denial of service. Let’s take a closer look.
Server misconfiguration and Slowloris DoS attack
Let’s consider a freshly installed Apache server hosting a simple static page:
If the server version is old, we may easily be able to carry out a denial of service on the platform, especially if the server configuration has not been affected.
To do this, we can use a tool called ” slowhttptest “, which can be used to carry out several types of denial of service attack. For this example, we are going to carry out an attack called “slowloris”, which belongs to the category of application layer attacks.
How a Slowloris attack works?
The principle of a slowloris is to send specially-formed HTTP requests in order to keep as many connections as possible open with the victim server. If the server does not manage its connections correctly, it will no longer be able to establish new connections with legitimate users and the denial of service will be effective.
So, with a simple command, the server is no longer accessible:
It is impossible to completely protect against this type of DoS. However, it is possible to drastically minimise the consequences of such an attack on an Apache server.
How to prevent this type of DoS attack?
The simplest solution is to install an Apache module called ” reqtimeout “, which has been installed by default since version 2.2.15.
This module makes it easy to define maximum request reception times and minimum data transfer rates. If the times or rates are not respected, the server will close the connections concerned.
The default configuration of the module is shown below:
RequestReadTimeout header=20-40,minrate=500
RequestReadTimeout body=10,minrate=500
With this configuration, once the connection has been made, the server allows the client a maximum of 20 seconds to send the first headers of the request. And for each 500 bytes of header data received, the server will increase the basic delay by one second, but never beyond the maximum delay, in this case 40 seconds.
The same applies to the second line, which is used to analyse the body of the request. After the connection, the server gives the client a maximum of 10 seconds to send the first data. For each data packet sent over 500 bytes, the delay is increased by one second, with no upper limit.
This second line also provides protection against another type of attack: the slow body or ‘R-U-Dead-Yet’.
You can, of course, lower the delay values considerably and add an upper limit to the “body” parameter. But this can be a problem for legitimate users. You should therefore change the default configuration to suit your own needs.
In our example, we only have a simple static page. We can therefore lower the values drastically:
RequestReadTimeout header=1-2,minrate=500
If we launch a slowloris attack with or without the module, we get:
At the end of the tests, the slowhttptest tool produces a graph summarising the attack. On the first graph, we can see that the green line representing server availability plunges to 0.
So, without the reqtimeout module, the server is unavailable for the duration of the attack. With the module, the attack was practically stopped because the server ended up closing all illegitimate connections.
Poor implementation of a web application feature
Sometimes, a vulnerability that enables an attacker to carry out a DoS attack is simply the result of an error or oversight when implementing a specific functionality in a web application.
An example might be an export function that generates a very large amount of data and can be launched using a simple button.
If the developer responsible for this functionality has not developed any safeguards, a malicious user could very well click on the button a very large number of times or launch thousands of export requests in order to launch several export processes in parallel.
This would have the effect of slowing down or even stopping the application altogether, requiring too many resources from the server.
In this case, to correct the denial of service, you could, for example, implement a back-end check to see if an export is already in progress, and if it is, the application will not be able to launch a new one until the current export has been completed.
In addition to poor implementation, a DoS can also be caused by a particular technology or language, such as GraphQL or XML.
DoS attacks on GraphQL APIs
With GraphQL, which is a query language for APIs, it is possible to create a DoS in different ways depending on the technology used and the configuration.
For example, consider the following GraphQL schema:
In this case, it is possible to call the “BlogPost” object with the “getBlogPost” query and its fields: “id”, “image”, etc. GraphQL also allows you to create ‘fragments’, which are a set of fields chosen by the user and which can be used several times in several queries, so that the user does not have to rewrite the entire query and all the fields each time.
However, a malicious user can use this principle of fragments to create an infinite loop.
All they have to do is create two fragments that call each other. If the user makes a request to call the first fragment, it will call the second fragment, which in turn will call the first fragment, and so on, slowing down the application or even stopping it altogether.
Below is an implementation of such an attack:
This implementation shows that fragment A calls fragment B, and fragment B calls fragment A, forming a loop. In the query, fragment A is called, which will launch the infinite loop.
To correct this behaviour, it is recommended not to use GraphQL implementations that allow fragment recursion.
In general, to counter DoS attacks on a GraphQL API, it is recommended that you use GraphQL implementations that support the ” Query Depth limit ” and ” Query Cost Analysis ” features, which allow you to define the field nesting limit and calculate the cost for each field call, thus blocking queries that exceed these limits.
XML Bomb DoS attacks
Finally, applications using XML to communicate between the client and the server can also be vulnerable to a DoS attack called the “XML bomb” or “Billion Laughs Attack”.
The principle of this attack is to create several entities that each reference the previous entity several times until arriving at the original entity, which is any string.
The best-known example of this attack is as follows:
In the image above, we can see that the “lol9” entity calls the “lol8” entity 10 times, which in turn calls the “lol7” entity 10 times, and so on until we arrive at the “lol” entity, which is the “lol” string.
Once parsed, the final XML block will contain 109 ‘lol’ strings, which is equivalent to 1 billion ‘lol’ strings, hence the name ‘Billion Laughs Attack’.
This operation requires a huge amount of memory from the server, which will slow down the application or even stop it.
To protect against such an attack, it is possible to disable the use of external entities and possibly set a limit on the use of resources used by the XML parser.
Exploiting vulnerable components to carry out a DoS attack
In addition to poor server configuration or implementation, it is also possible to carry out DoS attacks through vulnerable components used by the application.
In 2023, several thousand CVEs relating to DoS were published.
For example, the CVE-2023-20863 vulnerability affects the widely used “Spring” Java framework on versions prior to 5.2.24 release, 5.3.27 and 6.0.8. This vulnerability enables a denial of service to be performed using a specific SpEL (Spring Expression Language) expression.
To protect against this type of DoS, it is important to regularly update the components used and to implement a patch management process in order to:
- Delete unused components.
- Regularly make an inventory of the versions of all the components used and their dependencies, i.e. the components they use.
- Keep abreast of the latest major vulnerabilities and update the components concerned.
- Only use components from reliable and official sources.
- Monitor components that are no longer maintained or that do not have patches for older versions.
How to prevent DoS Attacks ?
More generally, to protect against denial of service attacks and limit their impact, here is a non-exhaustive list of solutions that can be put in place:
- Implement rate limiting: It is possible to restrict access to the server to one or more IPs if they are considered to be malicious.
- Use one or more load balancers: A load balancer can be used to redirect incoming traffic equally to several servers so as not to overload a single server.
- Implement a WAF: A WAF or “application firewall” can be used to establish rules that can recognise and block malicious traffic before it reaches the server.
- Monitor network traffic: By constantly analysing network traffic, you can quickly detect a denial of service attack. The response to such an attack can be rapid and the damage limited.
- Keep components up to date: Having up-to-date components prevents attackers from exploiting known vulnerabilities in certain versions of components, which could lead to a denial of service attack.
Author: Lorenzo CARTE – Pentester @Vaadata