SQL注入介绍(本文更新中)

Sql 注入攻击是通过将恶意的 Sql 查询或添加语句插入到应用的输入参数中,再在后台 Sql 服务器上解析执行进行的攻击,它目前黑客对数据库进行攻击的最常用手段之一。
产生注入的原因是后台没有对用户传递的参数做过滤,或者过滤的函数可以被绕过。下面我们依次介绍注入以及对应sqli-lab(下文中为sqli)中的关卡。

union联合查询注入

这种注入一般用于页面有回显位置的注入,如sqli的前几关

下面先来介绍一下联合查询中使用到的库、表和对应字段:

  • 数据库:information_schema
  • 数据表:
    在上图的几个表中我们常用到以下三个
  • SCHEMATA:存储数据库名的表
  • Tables:存储数据库以及数据库中的表名
  • Columns:存储数据库、表、以及表中的字段。
  • 字段:
    数据库名:schema_name from schemata
    数据表名:table_name from tables
    字段名:column_name from columns

下面来说一下常用到的查询信息的函数:

@@HOSTNAME 主机名称
@@datadir——数据库路径
@@version_compile_os——操作系统版本
Select VERSION()  数据库版本信息
Select @@VERSION   数据库版本信息
Select @@GLOBAL.VERSION  数据库版本信息
Select database()   数据库名称
user() 系统用户和登录主机名
current_user() 当前登录用户和登录主机名
system_user() 数据库系统用户账户名称和登录主机名
session_user() 当前会话用户名和登录主机名

再来说一下我们联合查询注入是用到的函数:

  1. order by
  2. union/union all
    UNION 操作符用于合并两个或多个 SELECT 语句的结果集。
    请注意:UNION 内部的 SELECT 语句必须拥有相同数量的列(这也是为什么演使用order by要将列数找出来的原因)。列也必须拥有相似的数据类型。同时,每条 SELECT 语句中的列的顺序必须相同。
    默认地,UNION 操作符选取不同的值。如果允许重复的值,请使用 UNION ALL。

    还有一点需要注意,要将原始查询的值设置为不存在的值,看了上面的图大家也应该会明白是为什么。
  3. group_concat()
    GROUP_CONCAT()函数将组中的字符串连接成为具有各种选项的单个字符串。
    我们平时进行查询是是将返回值作为数组一行行的显示的,但我们回显位只有一个,这时候我们就需要用到group_concat()了

GROUP_CONCAT()函数将组中的字符串连接成为具有各种选项的单个字符串。

下图演示了group_concat的功能

使用联合查询我们可以完成sqli中的Less1-6,5和6属于盲注,但使用的也是union联合查询。

盲注

盲注的本质就是猜解,在没有回显数据的情况下,我们只能靠‘感觉’来体会每次查询时一点点细微的差异,而这差异包括运行时间的差异和页面返回结果的差异。
对于基于布尔的盲注来说,我们可以构造一条注入语句来测试我们输入的布尔表达式,而这布尔表达式结果的真假,决定了每次页面有不同的反应。
对于基于时间的盲注来说,我们构造的语句中,包含了能否影响系统运行时间的函数,根据每次页面返回的时间,判断注入的语句是否被成功执行。
在盲注时我们会用到以下函数:

Length()函数 返回字符串的长度
Substr()截取字符串
left()  从左侧截取a的前b位
mid(a,b,c) 截取字符串a,从b起到c位  
Ascii()返回字符的ascii码
sleep(n):将程序挂起一段时间 n为n秒
if(expr1,expr2,expr3):判断语句 如果第一个语句正确就执行第二个语句如果错误执行第三个语句
regexp  正则匹配
like 相似匹配

基于布尔的盲注

以sqli的Less 5来举例子,当sqi语句正确时,页面输出You are in......,不正确时显示错误


根据这个可以判断出来大致的查询语句,但无法获取到信息,我们可以通过上面介绍的函数来尝试判断数据库的名称,如:

left(database(),1)>'s'

通过改变位置和单引号中的字符和页面回显来判断每一个字符分别是什么。这个需要写脚本来测试了

基于报错的盲注

当sql语句出现错误时,会将sql报错回显,这时候我们就可以进行基于报错的盲注。其原理就是将回显的信息通过构造的语句回显到报错信息中,可以类比编程中raise的思想。
这个我们在Less13中会详细介绍,在Less13中我们详细讲解,链接会在less13文章写完后更新到这里。

基于时间的盲注

常用函数:
If(exp,v1,v2):如果表达式 expr 成立,返回结果 v1;否则,返回结果 v2 Substring(s,n,len):获取从字符串 s 中的第 n 个位置开始长度为 len 的字符串
Sleep(duration):在duration参数给定的秒数之后运行

注入思路:
基于时间盲注的一般思路是延迟注入,说白了就是利用sleep()或benchmark()等函数让mysql执行时间变长并结合判断条件语句if(expr1,expr2,expr3),然后通过页面的响应时间长短来判断语句返回的值是TRUE还是False,从而猜解一些未知的字段。

注入流程(以获取数据库版本信息为例):

  1. 确定注入点及注入类型
  2. 使用if判断语句,猜测version()的长度并用sleep函数作为判断依据
  3. 重复步骤2直至获取真正长度
  4. 使用if判断语句,猜测version()的第一个字符的ascii码并使用sleep函数作为判断依据构造注入语句,
  5. 重复步骤4,直至获取全部长度的版本字符的ascii码

搜索型注入

SQL中使用like,%,_来匹配内容,用于页面搜索

SQL写入、读取文件

写入

相关函数
into outfile()
into dumpfile() # 使用二进制写入文件
使用sql写入文件必须包含两个条件

  1. 知道绝对路径
    知道绝对路径是一个难点,可使用@@basedir,@@basedata辅助获取绝对路径

  2. 拥有权限
    语句:

select * from user where id=1 and union select 1,2,'' into outfile '\var\www\a.php'

会报错,因为没有返回结果

读取

sql 使用load_file()、hex()、replace()读取文件,hex嵌套load_file()将读出的数据作为16进制输出,可以解决乱码的问题

同时读取文件也需要两个条件:

  1. 必须在服务器本地
  2. 欲读取文件必须小于 max_allow_packet

POST注入

存在与数据库交互的地方也有表单,与get注入相同,不过在body体中传值

另类注入

base64 注入

base64注入是针对传递的参数被base64加密后的注入点进行注入。这种方式常用来绕过一些WAF的检测。

XFF 头注入

通过修改X-Forwarded-For头对带入系统的dns进行sql注入,从而得到网站的数据库内容。
HTTP头文件里的X-Forwarded-For和Clien-IP一样都是获取访问者真实IP的语句
X-Forwarded-For:简称XFF头,它代表客户端,也就是HTTP的请求端真实的IP,(通常一些网站的防注入功能会记录请求端真实IP地址并写入数据库or某文件[通过修改XXF头可以实现伪造IP])。HTTP头文件里的X-Forwarded-For和Clien-IP一样都是获取访问者真实IP的语句。

宽字节注入

宽字节注入与HTML页面编码是无关的
这里先要搞清楚几个概念:

  1. 宽字节:一般指Unicode编码的字符集,通常用两个字节表示一个字符,原有的英文编码从单字节变成双字节,只需要把高字节全部填为0就可以。
  2. PHP中编码为GBK,函数执行添加的是ASCII编码(添加的符号为“\”)
  3. MYSQL默认字符集是GBK等宽字节字符集。
  4. PHP addslashes函数会将输入的url中的值进行转义如:%DF' ——> %DF'
    原理:
    MySQL使用字符集位GBK的话会将addslashes转换过的%DF%5C%27进行解析,由于使用的是GBK所以就将%DF%5C认为是gbk编码,%27,也就是单引号成功的饶过了addslashes函数的转义。
    演示参见Less-33(后期less33完成后添加链接)

使用sqlmap进行辅助检测

sqlmap -u "url?id=1%DF%'" --search --level 3 --risk 1 --thread 10 

cookie注入

cookie注入其原理也和平时的注入一样,只不过说我们是将提交的参数以cookie方式提交了
Less-20

二次注入

二次注入可以理解为,攻击者构造的恶意数据存储在数据库后,恶意数据被读取并进入到SQL查询语句所导致的注入。
Less-24

特殊字符的绕过

绕过注释符过滤

MySQL中的注释符

  • --+/--空格
  • /* 多行注释内容 */
    去除注释符的代码
preg_replace(mixed $pattern, mixed $replacement, mixed $subject)
# pattern 搜索的模式;字符串、数组
# replacement 用于替换的字符串或数组
# subject   被替换的字符串或数组
posted @ 2020-12-21 09:24  巨核单线程  阅读(188)  评论(0编辑  收藏  举报