Category: Injection Attacks

  • SQLi Series: SQL Timing Attacks

    In the previous post we built a web page and connected it to a SQL server in order to test and learn about SQL injection. In the previous application the website returned data to the web page making it easy to gather information from the database as the info was printed out.

    What happens if the web application does not print the data from the SQL query. Well, there are still ways to gather data. SQLi attacks where the results are not displayed are referred to as Blind SQL Injection. Of course, this makes the attack more difficult, but these are by far the most common SQLi vulnerabilities, and attackers don’t stop just because they take extra effort.

    One such way is using timing. MySQL servers have a Sleep function which causes the server to sleep for the specified number of seconds. You can use this in conjunction with comparatives allowing the dumping of the database.

    A Refresher

    We’re using basically the same application as last time, except that this time the application only returns success or failure depending on whether the username and password entered are correct or not. As a side note, a success fail message can be used much the same way, but this blog will discuss timing.

    This is the response when the username and password entered were correct:

    A success when the username and password are correct

    And this is the response when the username and password did not match:

    A failure when the password is incorrect

    Now we can login as we did last time by closing the SQL quote and commenting out the rest of the query, but we’ve already gone over that in the first blog in this series. So let’s explore dumping information from the database instead.

    Success when the password is incorrect using a SQLi attack

    Useful SQL Functions & Clauses

    In order to pull information from the database we will use a number of MySQL commands and features.

    SLEEP() Function

    The SLEEP function will cause the server to wait for the specified number of seconds before returning the information.

    Example from the command line:

    The SLEEP function

    As we can see the query takes five seconds to complete.

    SUBSTRING() Function

    We will need a way to test one character at a time, so we need a way to get one character from the returned info so we can compare it. For this we use SUBSTRING():

    SUBSTRING(String, Position, Length)
    The SUBSTRING function

    IF() Statement

    This is how we branch in MySQL.

    IF(Condition, Value if true, Value if false)
    An IF statement

    For the Value if true and Value if false we can do more than just add return values. For instance, we can put the SLEEP function right in the IF function.

    Using the SLEEP function in an IF statement

    We can see that, when the condition was true, the server waited for five seconds.

    COUNT() Function

    There will be times when we need to know how many of a thing we have. For instance, we might need to know how many columns are in a table or how many rows.

    Now, in the database I’m using for testing, I know that there are three columns in the users table.

    Here is an example using COUNT showing that.

    The COUNT function

    DATABASE() Function

    We can get the current database in use by calling the DATABASE() function:

    The DATABASE function

    Querying Database Schemas

    If, for some reason, you need to pull the databases manually, maybe because one isn’t set or you want to see what else is out there, you can use this query:

    SELECT table_schema FROM information_schema.tables WHERE table_schema NOT IN ( 'information_schema', 'performance_schema', 'mysql', 'sys' ) GROUP BY table_schema;
    Querying the database schema

    We should note that default databases are removed by the NOT IN() phrase.

    Getting Tables

    We can query the information_schema database to get tables in a database:

    SELECT table_name from INFORMATION_SCHEMA.tables WHERE table_schema='DATABASE';
    
    Getting tables using the information_schema

    Getting Columns

    We can also query the information_schema database to get the column names in a table:

    SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA='DATABASE' and TABLE_NAME='TABLE_NAME';
    
    Getting columns using the information_schema

    Comparative Queries with the LIKE & BINARY Functions

    = does not always mean equal. With the equal sign we can see how a capital A and a lowercase a are equal. Which is not true in a case sensitive language.

    An IF statement showing that the equal sign doesn't always mean "equals"

    To get around this we can use LIKE BINARY to compare. Here we find that a capital A and a lowercase a are not the same:

    Using LIKE BINARY to find strings that are exactly equal

    CAST() Function

    Sometimes when comparing things, it helps to cast items to a known type.

    Here is an example of casting 9 to a character:

    The CAST function

    LENGTH() Function

    When trying to figure out what a string is, it helps to get the length of the string:

    The LENGTH function

    LIMIT & OFFSET Clauses

    Given that we are using Blind SQL, we can really only test one thing at a time. This is where limiting the amount of returned data comes in handy with the LIMIT clause.

    The LIMIT clause

    We can step down the list using the OFFSET clause. Note that we increase the offset to one less than the count as that will be the last item.

    Using the OFFSET clause

    Bringing It All Together

    Now that we have all the tools we need, let’s put them together and pull info from the database.

    Basically, we will check character by character. First thing we would want to find is the database name. We should probably first figure out how long the database name is.

    Since we are using conditionals, it might be easier to use the username part of the query, that way we don’t need to have the right password.

    Closing off the SQL code after the username so that we don't need to know the password to perform our attacks

    First we see if the length is 1. It’s not, as the response comes back in less than five seconds.

    Discovering that the length is not 1

    Next we try 2, 3, and 4. We find out that 4 is correct, as the application takes longer than five seconds to respond.

    The Length is 4

    Now we need to figure out the letters in much the same way. Now we use the SUBSTRING function to test one letter at a time.

    Testing Letters for the Database Name

    To make things easier, I used Burp Intruder to send the letters automatically, instead of manually.

    We find that the letter S takes five seconds to respond. Now we know the first letter is S.

    Discovering that the first letter is "S" because there is a delay

    Next step is to test the second character.

    Testing the second character

    And we find that the second letter is Q.

    Finding that the second letter is "Q" using a timing attack

    Now, since I created the application, I know the database name is SQLi so let’s move on to getting table names.

    First we use some weird wizardry to discover the number of tables in the database, combining several of the functions we saw above:

    Getting the number of tables in the database

    Here we are getting the count of tables in the SQLi database. We find that there is only one table.

    Now let’s get the table name.

    Let’s start with getting the length of the table name.

    Getting the Length of the Table Name

    We find that the length of the name is five. With the length we can start grabbing the chars.

    Here’s the query we will use.

    Getting the table name one character at a time

    Basically, we are asking for all the table names for tables in the SQLi database. We grab the first one and then use substring to test one character at a time.

    Using Burp Intruder we find the first character is u. Repeating we find that the table name is users.

    Using Burp Intruder to find the character "u" with a timing delay

    Note:

    When retrieving names with this method, knowing the length is not truly required. When trying to compare to additional characters – say position six in the table name – it will always return false, meaning that the delay will never occur. If all the possible results stay under the delay, we know that we have the entire string. I like the idea of using the length to make sure I don’t miss something, but it’s not absolutely necessary.

    Now that we have the table name, it’s time to start getting data from the table itself. First, we need to know how many columns there are in the table.

    Finding There are 3 Columns

    When using the COUNT function to learn the number of columns, we find that there are three, as that’s when the sever takes more than five seconds to respond. With the number of columns in hand, let’s get those column names.

    This is similar to getting the table name but just querying different information.

    Here we get the length of the first column name:

    Finding Length of First Column Name

    And next the column name itself.

    Getting the Column Name

    Since we are getting information in the same way, this is very repetitive, so I’m going to assume you get the idea and go through this quickly.

    As an example, I’ll show how to get the second column’s information, which just means adding an OFFSET to the limit:

    Getting Length of Second Column

    Here we get the first letter of the second column:

    Testing Name of Second Column

    The second column is password, so, as expected, we find that the first letter is p.

    With all the table information, now we just need to start grabbing the data from the table. We can start by seeing how much data is in a table.

    Since this is a small test database, there isn’t a lot of data, so we can count the number of items and compare it to numbers we retrieve easily. On larger sets you may have to be more careful or smarter in gathering info. But this is a basic writeup giving the ideas, and I’ll leave that as an exercise to the readers.

    With this database, we find that there are only three records in the table:

    Getting Amount of Data in Table

    Now let’s get the first username from the table:

    Getting the Username

    And finally, we get their password:

    Getting the Password

    In Conclusion

    Timing attacks, as with all Blind SQLi, take a good deal of time and patience, but the rewards can be discovering credentials to login to the database or sensitive customer information like PII (Personally Identifiable Information) and financial data, like credit card numbers.

    As with all injection attacks, the remediation is to always validate user input. Raxis recommends keeping a list of whitelisted characters and deleting other characters before they process against the database. Cleansing data to be certain that user input is always treated as text (and not run as a command) is also key to this process.

    Understanding how to perform attacks like these are critical for web and mobile application penetration testers, just as understanding the idea of how they work is key for application developers so that they can build safeguards into their apps to protect their data and their users.

  • SQLi Series: An Introduction to SQL Injection

    Web applications often need to store data to better serve their customers. An example would be storing customer login information or comments submitted by users on the webpage. There are many ways of storing data for customers, but a popular way is to store the information in a SQL database.

    A common and basic use of web applications and SQL databases is to handle user login information and functionality. In many web applications a user submits a username and password into a form. The web application takes the submitted data and searches the database to determine if it’s a valid credential set. If it is, then the web application will log the user in.

    SQL Injection

    If the web application does not properly handle user input, an attacker might be able to create malicious input that changes the SQL query that performs that login task behind the scenes. Such SQL injection attacks take a lot of manual effort to discover and exploit, but they are a critical part of the web application penetration tests that we perform at Raxis.

    This blog explains how an attacker could find and exploit a SQL injection, or SQLi, vulnerability.

    Creating an Exploitable Login Webpage

    Let’s build a simple web application that asks for a username and password and returns the user’s ID. In order to help show the SQL injection attack, the application will also show the query used and the input from the login page. The SQL code the application uses (with user input parameters filled in) can be seen at the bottom of each screenshot.

    First let’s take a look at the results for the admin logging in normally.

    Successful login showing SQL query

    We can see that the user entered the admin username and password. We also see that our sample PHP web application uses a query where the username and password must match for success. If both match then, for our testing purposes, it returns the user ID which is printed out at the bottom.

    Here the admin’s account has the ID of 1.

    In the next example, the admin username is entered correctly, but the wrong password is supplied.

    Unsuccessful login showing the SQL query

    Again we can see the information that was input into the application and the query. However, since the password does not match the one in the database, we don’t get the user ID.

    Exploiting the Webpage to Login

    In the example queries above we saw that the username and password input was passed into the query without modification.

    So what happens if we close the single quote around the username?

    Attempted SQL injection with a single quote

    We see that, even though the correct password was entered, the single quote at the end of the username prevents the query from returning a correct result. In this case we get the same error message as if the username and password were incorrect, but other web applications might crash in different ways indicating there was a backend issue.

    In MySQL the # symbol denotes a comment, which makes the database ignore everything after it. Let’s try adding a # after that single quote we just added:

    Successful SQL injection bypassing the password

    Now we see that, even though we submitted the wrong password, the application considers the SQL query successful and returns the correct user ID. The question is What is happening here?

    Let’s take a closer look at the query and the input from the user.

    The input in the username field has injected two special SQL characters: the (single quote) and the #.

    This changes the query itself because the user input is directly inserted into the query.

    Highlighting that the MySQL # comment symbol allowed the SQL injection to work

    The single quote closes the username entry so that the text that comes after is read as part of the SQL query. This means that the # is interpreted as the comment symbol, meaning that the rest of the query is simply ignored.

    Basically, that means that the query is now just running as

    SELECT id, username, password FROM users WHERE username=’admin’

    Since the admin user exists, we get the successful result of the user id of 1, even with the wrong password.

    This also means that we can login as any user, provided that we know their username. Just change the admin username to the desired username.

    Using the same injection string to login as another user

    Exploiting the Webpage to Get Data

    Now logging in as any user is fun and all, but what else can we do? Well, we can come up with SQL queries that dump information from the database.

    Let’s use the UNION operator to inject another SQL query that goes along with the query created by the application. We should note that, since the sample web application only shows one column at a time, we need to switch what we are asking for first so that the application will show us more information.

    Here is what happens when we add a UNION SELECT for all the user IDs from the users table to the SQL injection we are entering in the username field:

    SQL injection adding UNION SELECT to get a list of all user IDs.

    After asking for the IDs, we enter a new SQL injection and ask for the usernames:

    SQL injection adding UNION SELECT to get a list of all usernames.

    And finally, we perform a SQL injection requesting the passwords:

    SQL injection adding UNION SELECT to get a list of all passwords.

    A Quick Note on Password Hashes

    This is a good time to note why using password hashes (instead of saving passwords in plaintext) is a good idea. If password hashes were in use, an attacker would have to crack the passwords in order for them to be useful in a SQL injection attack.

    Automated Exploitation with SQLMap

    While we can do attacks such as these manually, sometimes, after identifying a vulnerability, it is easier to use tools to exploit it for you. In real life scenarios, SQLi attacks don’t return the SQL statement, and it takes some trial and error to discover how the application is reacting to our input.

    My go-to tool for SQL injection attacks once I find a sign of them is always SQLMap. Here is a screenshot of SQLMap dumping the users table from the SQLi database the web application above uses.

    The SQLMap tool performing the same exploit we did manually

    SQLMap makes it a lot easier to dump information from a database when an application is susceptible to SQLi attacks. While here it dumped the same information we just did, it is capable of finding every table and column and dumping everything.

    More Than SQLi

    We should also note there are other ways of getting information from a database, including timing attacks in which a database waits to respond if something is true while responding quickly if it’s not. Timing attacks allow us to guess what input is valid and what is not valid. Maybe we will take a look at a timing attack example in another post.

    In Conclusion

    Now that we have a basic understanding of what SQL injection is and the types of exploits that can be done with it, my next posts in this series will go into specific attacks and how to perform them.

    As always, remember that these tutorials are guides for penetration testers and people looking to understand their penetration test results better. Attempting these attacks on any sites that don’t belong to you or where you don’t have legal documentation granting you access to perform ethical penetration testing is illegal and punishable under law.

  • Hackers See Opportunity Where You See Only a Button

    People are often surprised to find that a hacker doesn’t only attack a website through the authentication process. Our team members are experts at demonstrating why just enforcing password policies and lockout times doesn’t fully protect applications.

    In this article, we’re going to pull back the curtain and show you how hackers use web proxy tools to help exploit applications in ways you might never expect.

    How the Proxy Tool Works

    The proxy tool is software that follows the path data takes step-by-step from your device to the application server. Several such tools exist, but Burp Proxy (included in all versions of Burp Suite) is one of the most popular. Using Burp Proxy, hackers can bypass the user interface – the page you see when entering data – and change the information before it is sent to the application server. This makes it possible to avoid client-side controls, such as those that check that a phone number is only numeric or that an email address is formatted correctly. If the application server expects the client-side controls to have already validated data, the server code may not have all of the proper protections in place.

    In the image below, Burp Proxy, in “Intercept” mode, shows each step along the path that data follows from your device to an application server. The tool allows a user to tab from step to step and change the data that was input originally. If security features are built into the client (the interface you see) but not present on the application server, the proxy enables hackers to enter compliant data first, but change it however they want before it reaches the server.

    Burp Proxy in Intercept Mode shows the path your data travels

    One example of how hackers exploit this setup is through the commonly used buttons or checkboxes found in many apps. Most app developers are cautious about user input fields, but, because buttons, checkboxes, and radio buttons apparently limit data entry to “on-off” or “yes-no” choices, they often see little inherent risk. The problem is that, even though the user options are limited at the interface (client-side), they may not be limited by the code on the server itself (server-side).

    How a Proxy Tool can Reveal a Vulnerability

    The three illustrations below show how even a simple “submit” button can present opportunities for hackers.

    The choice here seems straightforward — either you click the button or you do not. But that choice masks what happens after you click “submit.”

    Save credit card information checkbox and submit button

    “Submit” is really just a request being sent to the server. Here, using Burp Proxy to intercept the data, we can see the request as it will appear to the application server.

    Unmodified GET request intercepted

    Now, rather than a simple yes-or-no choice, a user can modify the data any way they’d like and enter it by pressing the “Forward” command.

    Request modified with longer text
     How Hackers Turn the Exploit into an Attack

    With the ability to effectively bypass safeguards on the client-side interface, hackers can send information directly to the application server. Here are a couple of examples of the types of attacks they can execute if the application server is not secure. (For clarity, we’ll use text-based fields, rather than check-boxes in these examples.)

    Example 1: Cross-Site Scripting (XSS)

    Cross-site scripting (XSS) is a reflected attack that injects malicious client-side executable code into web application parameters to be returned by the application output and ultimately executed by the browser. Because it appears that the script is from a trusted source, the end-user’s browser accepts it and runs the script, permitting the attacker to take actions on the application’s behalf, such as accessing cookies and session tokens as well as other sensitive data. (Source: Raxis Glossary).

    The following walk-through demonstrate how a simple guestbook submission form request works normally and then how an attacker can use a web proxy to insert malicious code.

    This is the submission form as it appears to users:

    Guestbook submission form as it appears to web users

    Our Burp Proxy tool reveals the actual request sent to the application server:

    Captured form submission

    Here the attacker enters an innocuous submission that should not be caught by client-side injection controls:

    Attacker enters submission on web form

    And now the attacker captures the entry using Burp Proxy:

    Unmodified form submission in proxy tool

    Before allowing the proxy tool to move to the next step, the attacker replaces the original harmless data with a malicious script:

    XSS Payload inserted into form submission

    The application server, without server-side controls to stop it, accepts the script and returns the payload to the browser. This is what the attacker sees in Burp Proxy:

    JavaScript Payload Returned in Response Body

    And here we see the successful cross-site scripting result in the browser:

    XSS script executes when entry is displayed on the resulting webpage
    Example 2: SQL Injection (SQLi)

    In this attack, a SQL query is injected into the application via input parameters. A successful attack could read sensitive data from the database, modify data in the database, execute operations on the database (including administrative operations), recover files on the DBMS file system, or issue commands to the operating system. (Source: Raxis Glossary)

    Here we demonstrate how a user ID field can be manipulated to enable a SQLi attack.

    We start with a simple user ID entry field with a submit button where we enter a name and submit:

    Web form with textbox and submit button

    Again the attacker intercepts the submission using Burp Proxy en route to the application server.

    Unmodified GET request intercepted

    As above in the XSS exploit, the attacker then modifies the data in Burp Proxy, this time to include escape characters and a SQL query:

    Request modified to contain SQL injection payload

    With no server-side controls in place to stop the attack, the server returns the data requested in the SQL database query. This is what the attacker sees in Burp Proxy:

    Request returns all users from database

    And here we see the successful SQL injection result in the browser:

    All user records returned from database
    Summary

    It’s tempting here to focus on the Burp Proxy tool and its capabilities, but the more important point is to recognize that vulnerabilities can exist in places we as users might not think. Something that seems innocuous, like a simple submit or on/off button, can be manipulated by a hacker with relative ease. The same is true for any field, button, or widget that sends a request to an application server.

    Remember that the mindset of a hacker is always to look at something as it’s expected to be used, then attempt to use it differently. That’s why pentesting by skilled professionals is so important. It takes trained, ethical hackers to prevent the work of their malicious counterparts.

    Would you like to learn how Raxis can help your organization? Reach out. We have a guaranteed, no-pressure approach, and – after all – we’re all on the same side.