Database DoS – Part 2: Get Judo Fit to Combat Diverse DB-DoS Attacks
Nov 5, 2013
Following on from the first blog (Is Your Database in the Crosshairs?) on the noteworthy subject of Database DoS, in this, the second part of the Database DoS blog trilogy, we focus on the attack vectors and, in doing so, our objective is to get you thinking about reviewing your own Databases from a DoS vulnerability point of view.
There exists a huge diversity of DB-DoS attacks. Many of them are dumb—they seem to be written by people who do not understand SQL and create horrible and absurdly inefficient queries. Then again, some exploits are so simple and clever that we are amazed that the vulnerabilities they target were not found in quality assurance tests (remember my example of zip code look ups in the first blog). Whether they are in fact clever or dumb, these attacks are effective.
For example, you could set up a couple different searches on a website, choose very broad lists of values, and hit “search.” The backend relational system starts to look at every record in every table, chewing up memory and waiting on slow disk reads, starving out legitimate user requests. It’s as simple as that.
Let’s look more closely at a couple different classes of denial of service attacks:
Abuse of Functions
The abuse of database functions is, by my count of reported vulnerabilities related to DoS, the single most common type of DB-DoS attack. There have been hundreds, and it seems like no externally accessible function is safe.
This class of attack is a bit like competitive judo. As you shift your weight in one direction, your opponent pushes you in the same direction to make you lose your balance and fall over. An attacker may use database features against you just like a judo expert uses your weight against you.
For example, if you restrict failed logins, attackers may try bad passwords until they lock legitimate users out. If you implement services to scale up automatically to handle bursts of requests, attackers can generate bogus requests to scale the database up—until it collapses under its own weight or, in metered cloud environments, you hit a billing threshold and service is shut down. There is no single attack vector, but a whole range of ways to misuse database functions.
This class of attacks is about attackers making a database function misbehave. Typically it occurs when a database command confuses the database, the query parser, or a sub-function enough to lock up or crash. Relational databases are complex gestalts of many interdependent processes, so the loss of a single service can cause the entire database to grind to a halt.
One example is an attacker sending malformed Remote Procedure Calls—incomprehensible to the parser—which cause it to simply stop. Malformed XML and TDS calls have been used the same way, as have SNMP queries. Pretty much every database communication protocol has, at one time or another, been fooled or subverted by requests that are formatted correctly but violate the expectations of the database developers in a way that causes a problem.
SQL injection is the best known type of functional abuse. SQL strings are bound into a variable passed to the database so it processes a very different query the application developers expected. SQL injection is
not typically associated with DoS. It is more often employed as a first step in a database takeover because attackers generally want to control if they can. That said, SQL injection is also known for crashing databases, so it serves both nefarious use cases. But keep in mind that anti-SQL injection products may not provide DB-DoS protection because SQL injection <> DB-DoS!
But back to judo. Remember that every function you have can be used against you.
Complex queries work by giving the database too much work to do. Attackers find the most resource-intensive process accessible and kick off a few dozen requests. These attacks are designed to exhaust a database’s resources, targeting memory consumption, processing power, or, in rare cases, I/O.
Computed columns and views:Computed columns are virtual, typically created from the results of a query and usually stored in memory. A view is a virtual table whose contents are also derived from a query. If the query selects a large amount of data, the results occupy a large chunk of memory. And if the column or view is based on a complex query, it requires significant processing power to create. Exposure of computed columns and views has been the source of DB-DoS attacks in the past, with attackers continually refreshing views to slow down the database.
Nested queries and recursion: Recursion is when a program calls itself. Each time, it recreates declared parameters or variables in memory. A common attack is to place a recursive call within a cursor FOR loop; after a few thousand iterations, the database runs out of cursors or memory and halts.
The IN operator: This operator tests whether a supplied variable matches any value within a set. The operation itself is very slow, even if the number of values to be compared is small. An attacker can inject the IN operator into a query to compare a large set of values against a variable that never matches. This is also called the snowflake search because it is like attempting to match two unique snowflakes, but the database continues to search regardless.
Cartesian products and joins: The JOIN operation combines rows from two or more tables. A Cartesian product is the sum of all rows from all tables specified in the FROM clause. Queries that calculate Cartesian products on a few large tables generate huge result sets—possibly as large as the entire database. Operations on a Cartesian product can overwhelm a database.
User defined functions: Similar to computed columns and views, any user-defined function gives an attacker carte blanche to abuse the database with whatever query they choose. Attackers have leveraged all of the above complex queries as user-defined functions when allowed. Attackers attempt to exploit any complex query they can access. All these abuses are predicated on the attacker being able to inject SQL into some part of the database or abuse legitimate instances of complex operations. A couple of complex queries running in parallel are enough to consume the majority of a database platform’s resources, badly slowing or completely stopping the database.
Bugs and Defects
Attackers exploit defects by targeting a specific weakness or bug in the database. In the last decade, we have seen a steady parade of bugs that enable attackers—often remotely and without credentials—to knock over databases. A single “query of death” is often all it takes.
Buffer overflows have long been the principal vulnerability exploited for DB-DoS. We have seen a few dozen buffer overflow attacks on Oracle that can take down a database—sometimes even without user credentials by leveraging the PUBLIC privilege.
SQL Server has its own history of similar issues, including the named pipes vulnerability. Attackers have taken down DB2 by sending UDP packets. We hear rumors at present of a MySQL attack that slows databases to a crawl. Attack specifics and targeted features vary, but the same basic attacks are used against new features every year. Database vendors constantly add new features and modules; as well as new ways to connect, communicate, and cooperate; and old attacks are revised to target new chinks in the armor. But all these exploits need a known defect, and the attacker needs to find vulnerable databases before they are patched.
To succeed at remote exploitation the attacker needs to guess—or probe—the type of database in use behind a web service, then send an attack that slows the database down, exhaust its resources, or cause a deadlock. Database developers and testers check to make sure new functions work, but they rarely try to obscure test cases or fuzz inputs with random parameters.
This is why, historically, so many bugs have led to DB-DoS. Each time a vulnerability becomes public, attackers “weaponize” exploit code and then attack every web application they can find. And this is why DBAs are at odds with security practitioners—the typical database patch cycle is 14 months, while security patches from major relational database vendors are released every three months. Worse, attackers often release exploit code within days of vulnerability disclosure.
While companies spend far more on applications and application development that they do on network infrastructure, the irony is security spending is the exact opposite. Security teams deploy the vast majority of their security controls at the network layer, which includes DDoS protections. There are many reasons for this, but for the most part it’s faster and easier to insert an appliance on the wire than place security in the application layer.
Negotiating with a DBA on how to implement and deploy security controls around a database is never going to be easy or fun, and finding solutions that are both effective and non-invasive is not an easy task. However, in order to address the attacks we discussed in this section, it’s essential. With attacks moving “up the stack,” DB-DoS protection is simply not addressed by your traditional DDoS products.
If you thought the previous sections looked a bit like a list of database features, you are right. Denial of service may target anything—including the way the application uses the database. Databases must expose functions to application platforms to enable data management. But if the application does not successfully protect those functions—such as with SQL Injection—the underlying database is exposed to anyone who uses the app. Phrased another way: If an application can be leveraged to misuse a database, it will be so used.
For example, one common attack against retail websites is to put a few thousand items in a shopping cart, continually adding new items and refreshing the cart. The database must validate each item is in stock, so it queries the inventory control database for each item in the cart on each refresh. An attacker may only need a couple concurrent shopping cart sessions to stall the site. Attacks leverage legitimate application and database functions, focusing on those that require complex processes running behind the scenes. It does not take long for an attacker to identify good targets: operations that are already slow to respond to input. Developers and DBAs tend to point fingers each another and deny their own responsibility, but there is no single way to address this type of attack.
Some of this discussion of DB-DoS over the past decade may look like ancient history. But while general DoS tactics have changed, the database specific attacks have not. DoS attacks in general are on the rise, and the most important change has been moving up the stack.
Database and application layer attacks have been somewhat born again, as the same old avenues and exploits are leveraged all over again. As new hacking concepts and approaches evolve, attackers look at the features and functions they have hacked previously to see how they can apply their new toys. We saw buffer injection attacks for over a decade because they continued to work as attackers found new areas of vulnerable database code. We continue to see SQL injection attacks because still they work. We see attacks against network protocols because DBAs still forget to configure them correctly.
In the next and final installment of this blog trilogy, we’ll focus in on counter measures. Thanks to Adrian Lane for the bulk of the content; and thank you, the reader, for taking time out to read this blog. Please stay tuned for the final chapter.
[i] Adrian Lane, Analyst and CTO. Adrian is a senior security strategist with 25 years of industry experience. He brings over a decade of C-level executive expertise to the Securosis team. He specializes in database architecture and data security. With extensive experience as a member of the vendor community (including positions at Ingres and Oracle), in addition to time as an IT customer in the CIO role, Adrian brings a business-oriented perspective to security implementations. He is a Computer Science graduate of the University of California at Berkeley with post-graduate work in operating systems at Stanford University.