WAF之SQL注入绕过挑战实录

首先要熟悉tencent WAF的部署环境,是在网络层,还是在应用层,如果在应用层是在到达apache(或nginx)之前还是之后。不同的部署环境决定了不同的绕过方法。通 过在TSRC上查看《主流WAF架构分析与探索》一文了解了tencent WAF 实现于服务器的安全模块内,这样的话,类似于十进制ip地址绕过网络层WAF防护gzip等一系列编码绕过也就无从谈起。

首 先想到通过畸形http包来绕过,尝试LOL /sql.php?id=1 and 1=1HTTP/1.1等,发现基本都被服务器过滤了,说明tencent WAF 在开发时还是吸取了不少经验的。经过不断尝试发现畸形数据包,参数污染等方法均告失败。只能把主要精力放在mysql一些语法特性上了,下面的几种思路基 本都是利用了mysql 自身语法特性来实现的。

首 先介绍一种绕过思路——采用%a0绕过。id=-1 union%a0select 1,2。服务器检测了union和select之间是否含有空格,如果union select同时存在且还有空格则视为一次sql注入攻击行为。但是有许多方法可以进行绕过例如union/**/select、 union%0dselect等,这里基本上都被过滤了,但是不知道是开发人员粗心还是故意放水,唯独留下了union%a0select 这个没有过滤。

除 了union%a0select似乎已经没有其他可以绕过检测的了,fuzz了一遍这次应该是真的了,但是功夫不负有心人,一种神奇的方法出现了—— union/*%aa*/select。咦?这个不是属于/*xxx*/应该是被防护了的怎么还可以呢?这是中文字符的特性利用中文字符配合注释符 bypass 所有规则。利用%e4等只要是中文字符开头的,就可以完成绕过检测!%a0之类的,已经补了。测试发现。union select可以共存,只要让检测不要认识是union 空格select就行。所以这里这样构造出一个特别的字符串。我们通过union+“特殊字符”+select拼出一个新字符串,让正则认为这是个类似 unionxxooselect这种,而不是union select 。 这样就能bypass检测。但是,要让数据库识别这个,就要想办法干掉这个多余的字符。服务在检测的时候,并不把/**/作为攻击特征,当然,这本身也不 是特征,但是如果我们利用这个符号把这个多余的字符干掉,就可以让语句正常执行了。因此,这里就是利用union/*中文字符*/select,完全 bypass。当然,还要保证这种中文字符不能构造一个汉字。

以上两种方法均可以绕过union select,以及select from进行随心所欲的注入,后面介绍的这几种就比较鸡肋了,仅仅能绕过mysql函数限制进行loadfile,或者获取一些环境信息。

由于WAF对敏感函数进行了检测,导致我们的version(),load_file()等函数无法使用,但是由于是正则匹配,我们可以使% 0b进行轻松绕过。例如:version()%0b,其他的特殊字符均被过滤了,%0b在这里成为了漏网之鱼。

同样的绕过函数的思路,我们可以使用`version`()的方法再次避免WAF的正则匹配,由于mysql 语法特性`函数名`()等价于函数名()再一次完美bypass。绕过了函数名我们如何select呢?这里我们需要用到十六进制盲注:

  1. id=1 and(select `load_file`(0x2f6574632f706173737764) is not null)
  2. 首先判断服务器某文件是否存在,例如这里我们用/etc/passwd文件。0x2f6574632f706173737764是/etc/passwd的十六进制格式。在判断确实存在该文件之后,我们可以通过:
  3. id=1 and(select `load_file`(0x2f6574632f706173737764)>0x726f66)
  4. 根据页面返回修改大于号之后的十六进制值,从而获取到该文件的十六进制内容。
  5. 最后一种思路是获取服务器的配置信息,通过id=instr(@@global.version,1)来获取global变量。@@global包含很多敏感信息,过滤了ascii,substr函数,仍可用instr来盲注。