Myql SLEEP函数和SQL注入

缘起

如果你审查过的慢查询日志或者网站access日志中,你可能都会看到如下的语句:

WHERE col.id = (select(0)from(select(sleep(90)))v)/*'+(select(0)from(select(sleep(90)))v)+'"+(select(0)from(select(sleep(90)))v)+"*/;

可能就是你网站启用后大概1小时候内就收到的日志,或者你Web服务器(nginx)访问中看到的。如果你是在Mysql慢查询日志中或者access日志中看到,并且该跳请求返回的状态码为200,而不是404,那么恭喜你可能中标了,被人Sql攻击了。本文虫虫就和大家以sleep()函数为介入来讨论。

SLEEP()函数

SLEEP(n),暂停数据库n秒。

不要混淆MySQL控制台中的sleep状态,它描述了连接的状态,SLEEP()函数做了一件事,就是暂停数据库的执行,直到设定的时间。那么该操作有什么用?为什么要用它呢?

通常,有一些操作需要一段时间来操作,操作时候需要暂时操作或者更新(比如数据锁,比如记录一个Pos点后,备份一个从库),当然也有可能是黑客攻击。

漏洞渗透和扫描

如果你的数据库和网站没有做安全措施,直接把端口暴露在公网上(比如ssh 22端口,mysql 3306端口),那么,很快就会能有扫描器对你的端口进行扫描渗透。所以虫虫以也提到过在主机防护中的条款:禁止把端口暴露在公网;修改常用端口。专门对于mysql,最常用的扫描渗透和安全审计工具是sqlmap。

sqlmap是使用Python编写的一款数据库sql注入扫描工具,目前支持常见的mysql、oracel、postgresql、sql server,access,db2,sqlite等数据的安全漏洞(sql注入)。

在sqlmap盲主扫描中,通常会Fuzzy各种sql语句,通常还会使用sleep命令。比如扫描那些使用旧的mysql或mysqli等非PDO的连接PHP MySQL网站,然后枚举易受攻击的AJAX命令列表或GET/POST结果,在输出扫描结果时候的通常需要中止执行。

sqlmap及同类工具可以并行攻击几十个站点,通过对这些网站强制数据库sleep一段时间(数字设定取决于个人经验),通过计数sleep的时间,来测试渗透命令中的有效性,这在安全界通常叫基于时间的盲注。

快速解剖

在本文开头,我们举了一个sql语句的例子,这是常用的盲注的典型语句。如果执行SELECT语句,其中的条件语句部分被替换为类似以下的内容,那么它将绝对锁定数据库:

WHERE col.id = (select(0)from(select(sleep(90)))v)/*'+(select(0)from(select(sleep(90)))v)+'"+(select(0)from(select(sleep(90)))v)+"*/;

注意该语句巧妙地使用各种运算符和分隔符。注意该语句,对只对拼写sql语句的程序有用,使用PDO该语句可以被过滤,不能执行的 。

PHP mysql注入示例

让我们写一个php的示例,来说问题。看以下函数:

上面的示例中,我们使用implode()函数生成以逗号分隔的ID列表。由于对输入没有任何验证,传入的数组中,可能是非法的具有SLEEP的命令或者dump 数据库表中的数据到展示页面。针对这种问题,你需要使用对传入的数据做验证,验证长度(根据实际需要限制参数长度,可以极大防止注入的成功)。

你可以使用PDO等链接框架,利用占位符代替(绑定)参数生成sql语句,并通过prepare做参数验,这样可以阻止绝大多数的SQL注入的值。

PDO并非灵丹妙药

上面我们也说通过PDO可以预防绝大多数的PHP Sql注入问题,但是他不是100%保证能解决所有问题。

如前所述,自己拼凑Sql的原始动态组合方法,让很多PHP系统处于危险之中

所以,一无所措的码农们不可避免地会通过谷歌寻求帮助他们:

上面是网上一个很流行的PDO使用教程之一,该代码使用PDO,但是和纯的手动拼凑Sql的并没有什么两样,也是非常危险的做法。

还有如下StackOverflow(一个知名的编程问答网站)上的的一个答案:

看到了么,这也是很糟糕的代码,但是还被接受了。在码农们接受的概念是"使用PDO可以防止sql注入",但是他们不知道PDO防止注入也是有前提的,那就是必须是用"?占位符绑定写SQL,然后prepare,然后execute",否则等于没有用。

不要小看sleep()

可能你觉得发现sleep()执行,并没有什么的?起码不会DROP你的数据库。SLEEP()很容易识别,并且在该阶段通常几乎没有啥害。但是通过,可以在通过盲注Fuzz测试数据执行大量的查询,并很快就找到有效的攻击EXP。

实际上,这就死sqlmap的核心功能。这种思路的一个问题是,在依赖于MySQL for UX/UI的生产Web项目中,通常的做法是将代码执行用户限制为仅具有SELECT权限,不给他DROP权限。但是SLEEP()使用只需SELECT权限。

SLEEP怎么禁止?

因为SLEEP函数的使用只需要SELECT,不需要任何特权权。并且可以作为"最安全的"MySQL命令执行。

它只是一个SQL注入漏洞,无法使用定时攻击暂停数据库执行或浏览数据(或对其进行dump)。而且一般通过简单的配置无法禁用SLEEP函数。MySQL可以在数据库,表和列级别做权限限制。当然如果能有办法简单这顶对某些危险函数的禁止也是有意义的(比如php.ini中的disable_functions配置)。

实际上sleep也给了我们一种防御思路,基于对该函数关键字的探测来实现sql攻击告警和防御。比如虫虫自研了一款web防火墙App-Waf(github:/ bollwarm/App-Waf)就是基于这样的探测原理,通过分析访问日志中的关键词,其中就包括了sleep函数,下面是我用的关键字规则(部分)。

本文中虫虫和大家一起以Mysql的sleep()函数为介入讨论了Sql注入的问题,总体上来说可以使用sleep()来枚举SQL漏洞,PDO绑定参数的方法擦可以防御Sql注入,sleep()一般无害,而且不会正常情况下很少用的到,但是可以变废为宝用他来做为探测攻击的手段。

关于更多的安全和Sql注入的问题关注虫虫公众号,虫虫会撰写文章和大家一起学习。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20181215A08EEY00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券