SQL注入
Posted Kiopler
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SQL注入相关的知识,希望对你有一定的参考价值。
0. phpStorm代码调试方法
phpstorm启动调试方法:
加上&XDEBUG_SESSION_START=PHPSTORM即可开始调试
phpstorm调试时动态修改变量方法:
调试时对特定变量按下F2即可修改变量内容或者右击按Set Value...选项
1. 联合查询注入
利用前提:
页面上有显示位
优点:
方便快捷, 易于利用
缺点:
需要显示位
细分:
- 字符型注入
实践一下:
成功注入:
可以构造如下来判定是否存在字符型注入:
- 整型注入
实践一下:
成功
联合注入利用order by和group by判断表的列数
order by后面是可以接列号的,比如以第一列排序就是order by 1 以此类推
如果说order by选择的列号存在,就会正常显示
如果选择的列号过大,就会报出如下错误
用这种方法二分法慢慢缩小范围很快能确定列总数,以此方便联合注入
如果不能使用order by, 则可以使用group by来进行判断列数
可以构造如下, 即后面接算数表达式, 如果1+2查询与直接写3结果一样则代表存在整型注入:
2. 利用注入列出所有数据库的方法
最重要的数据库为information_schema, 其中有3个非常重要的表:
- schemata表的schema_name包含数据库名
- tables表中table_schema对应数据库名, table_name对应这存在数据库内的表名集合
- columns表中column_name对应列名,table_schema和table_name对应数据库和表名
获取所有数据库名方法:
获取的结果:
获取特定数据库的表名方法:
获取的结果:
获取特定表的列名方法:
获取的结果:
3. Load_file以及into outfile的使用
通过mysql利用load_file()函数和selectt ... into outfile ...来读写文件
1. load_file()函数读内容
Windows下如果在mysql配置文件my.ini中
1. 默认secure_file_priv选项默认不存在(即secure_file_priv=null),查询时会显示为NULL。这种情况下不允许对任何文件通过mysql进行读写(mysql5.2以后的版本都默认是这个设置)
2. 限制mysqld的导入, 导出只能发生在/tmp目录下secure_file_priv=/tmp/
3. 不对mysqld的导入, 导出做限制 secure_file_priv=
Linux下则是/etc/my.cnf文件
利用mysql远程读取了一个文件
使用load_file函数读取文件内容需满足的条件:
- 绝对路径
- 必须是root读取文件的权限
- secure_file_priv不能为NULL
2. select into outfile写内容
不允许把文件名转成16进制来进行写入
使用select...into outfile...写入文件内容需满足的条件:
- 绝对路径
- 必须是root写入文件的权限
- secure_file_priv不能为NULL
- 能够使用单双引号(因为文件必须要单双引号)
尝试使用load_file读取本地内容:
获取的结果:
发现好像没有结果, 选择查看源码后立即就找到了文件内容
尝试使用select ... into outfile ...写入文件
4. Error-based SQL注入(报错注入)
利用前提:
页面上无需显示位, 但是需要输出sql语句执行错误信息, 比如mysqli_error()或mysql_error()
优点:
不需要显示位
缺点:
需要mysql_error()或者mysqli_error()报错信息
如果配合联合查询注入需要考虑列的问题
-- 这里注意报错注入中是2列,因为其中一列有错误。如果开始的select中有多列则要在后面联合注入内添加新的列
select 1, 2 union select count(*), (concat(floor(rand(0)*2), (select user())))x from mysql.user group by x;
第二种方法不需要考虑列的数目, 只要where后面即可:
select 1 from dual where 1=1 and (select 1 from (select count(*),concat((select user()),floor(rand(0)*2))x from mysql.user group by x)a)
来举一个例子:
extractvalue报错注入
这里通过extractvalue()进行报错注入, 内容显示有限制只能显示部分
为了解决这个问题利用substr函数来获取后面内容
extractvalue(xml string, 需提取的字符串)中原本后面应写入类似'/../../...'格式的字符串,但我们这里在最前面加上的是0x7e即~符。所以导致报错,其会返回需提取字符串内容,即我们需要的信息
updatexml报错注入
同样它也有显示不完整的问题,为了获取完整内容可以通过substr分段显示的方式获取
在sqli上尝试利用extractvalue报错注入和xmlupdate报错注入:
这是利用extractvalue报错注入:
这是利用xmlupdate报错注入:
5. Boolean-based blind SQL注入(bool盲注)
利用前提:
页面上没有显示位, 也没有输出SQL语句执行错误信息
只能通过页面返回正不正常
优点:
不需要显示位, 不需要错误信息
缺点:
速度慢, 耗费大量时间
这里使用了sleep()函数,如果执行成功会睡眠10秒
这里1=2绝对不成立,如果id是双引号包裹,那这里就能正常执行(双引号直接提取1忽略后面非数字内容),如果是单引号,应该是错误即啥也不显示。
这种方法通过一个个字母进行二分法判断来找到对应的用户名
为何会没有回显位?
如果碰到无论sql语句执行正确或者失败都没有回显的情况, 只能利用如下bool注入尝试注入并配合二分法,如果出现延迟即ascii位于对应范围内
尝试实验:
6. 堆叠SQL注入
这种注入方式出现的很少,因为现在使用mysqli_multi_query()函数,该函数并非多条sql一起执行,而是只执行一条。
如果想要执行多条sql语句,需要加上mysqli_next_result()执行。
这样就导致堆叠注入只会执行第一条sql语句,后方语句无法执行,看一个例子:
后面的select sleep(5)无法执行,除非mysqli_next_result()调用。
7. 宽字符注入
宽字符注入的目的是为了解决addslashes()之类的函数添加转义的问题。其使用的前提是mysql会使用宽字节,比如设置宽字节编码的sql语句:
set names gbk/gb2312/GB18030/BIG5...
利用phpstorm调试,举一个例子:
这里使用的是联合注入方式, 内部调用了3次preg_replace(), 把\\替换成了\\\\\\, 并转义了单引号和双引号。
函数返回后就发现单引号被转义了
如果把字符集设置成了gbk或者gb2312之类的宽字符。mysql会把ascii码大于128(%80)的字符当作汉字字符的第一个字节(汉字一共有2个字节, 大于128后面的那个字节会被连带作为汉字的第二字节)
利用这个特性,我们构造这样的注入语句
结果输入部分成这样
整条语句变成这样了,这就除去了转义的问题。
这样就成功显示了内容
如果发现单双引号被过滤了,那可以考虑使用宽字节注入。
如何快速判断是否有sql注入?
- 四则运算, 看是否返回对应的值, 比如2-1和1是否相等,如果相等可能是整型或者没注入问题
- 看是否报错, 利用'和"符号,看是否有错误信息
- and 1=1/and 1=2 看页面是否变化, 如果没有变化则很大可能没有注入
- 基于时间and sleep(10)看页面是否经过一段时间返回
注入方式分类:
- 联合查询注入
- 基于报错注入
- 基于bool注入
- 基于时间注入
- 堆叠注入
注入类型分类:
- 字符型注入
- 整型注入
(未完)
以上是关于SQL注入的主要内容,如果未能解决你的问题,请参考以下文章
面试题--如何防止sql注入,使用PreparedStatement的预编译,传入的内容就不会和原来的语句发生任何匹配的关系,达到防止注入的方法