当前位置: 首页 > news >正文

从一开始的网络攻防(十四):WAF绕过

基础知识

概念

BYPASS WAF实际上是去寻找位于WAF设备之后处理应用层数据包的硬件/软件的特性。

利用特性构造WAF不能命中,但是在应用程序能够执行成功的载荷,绕过防护。

那些特性就像是一个个特定的场景一样,一些是已经被研究人员发现的,一些是还没被发现,等待被研究人员发现的。当我们的程序满足了这一个个的场景,倘若WAF没有考虑到这些场景,我们就可以利用这些特性bypass掉WAF了。

例如我们现在需要bypass一个云 WAF/IPS/硬件 WAF,此处我们可以利用的点就是:

  1. Web架构层bypass
  2. Web服务器层bypass
  3. Web应用程序层bypass
  4. 数据库层bypass
  5. WAF层bypass
分类
云WAF

在配置云WAF时(通常是CDN包含的WAF),DNS需要解析到CDN的IP上去,在请求uri时,数据包就会先经过云WAF进行检测,

如果通过再将数据包流给主机。

主机防护软件

在主机上预先安装了这种防护软件,可用于扫描和保护主机(废话),和监听web端口的流量是否有恶意的,所以这种从功能上进较为全面。

modsecurity、ngx-lua-WAF这类开源WAF虽然看起来不错,但是有个弱点就是升级的成本会高一些。

硬件ips/ids防护、硬件WAF

使用专门硬件防护设备的方式,当向主机请求时,会先将流量经过此设备进行流量清洗和拦截,如果通过再将数据包流给主机。

软WAF

软件WAF则是安装在需要防护的服务器上,实现方式通常是WAF监听端口或以Web容器扩展方式进行请求检测和阻断。

工作过程

假设客户端访问url:htp/www.miku.com/1.php?id=1'and'1'='1,请求的数据是服务器上数据库中id为1的记录。

假设这台服务器使用了相关云WAF

域名解析

一个完整的过程,首先会请求DNS,由于配置云WAF的时候,会修改DNS的解析。

我们发送DNS请求之后,域名会被解析到云WAF的IP上去。

DNS解析完成之后,获取到域名信息,然后进入下一个步骤。

三次握手

HTTP协议是应用层协议,且是tcp协议,因此会首先去做TCP的三次握手

发送HTTP请求

发送HTTP请求过去,请求会依次经过云WAF、硬件IPS/IDS设备、硬件WAF设备、服务器、web服务器、主机防护软件/软WAF、WEB程序、数据库。

云WAF、硬件IPS/IDS、硬件WAF均有自己处理数据的方式。

TCP重组

在获取HTTP数据之前会做TCP重组,重组主要目的是针对互联网数据包在网络上传输的时候会出现乱序的情况,数据包被重组之后就会做协议解析,取出相关的值。

如http.method=GET,http payload=x等等。

这些值就对应了IPS规则中相关规则的值。从而来判断规则匹配与不匹配。

Web架构层绕过

寻找真实IP

云WAF通过修改DNS解析隐藏了真实IP地址

查找域名解析记录

利用邮件发送功能来抓包,获取真实IP

畸形数据包BYPASS

GET型请求转POST型

Content-Length头长度大于4008

正常参数放在垃圾数据后面

Web Server层bypass

Apache
畸形method

某些apache版本(version2.*)在做GET请求的时候,无论method为何值均会取出GET的内容,如请求为的method为DOTA2,依然返回了aid为2的结果。

如果某些WAF在处理数据的时候严格按照GET,POST等方式来获取数据,就会因为apache的宽松的请求方式导致bypass。

实例

我们使用实体机安装DVWA+phpstudy搭建测试环境,测试的内容是某些apache版本与waf解析request时的不同

改成任意一个非标准HTTP method都可以取出GET的内容

php+apache 畸形的boundary

php在解析multipart data的时候有自己的特性,对于boundary的识别,只取了逗号前面的内容,例如设置的boundary为--aaaa,123456,php解析的时候只识别了--aaaa,后面的内容均没有识别。然而其他的如WAF在做解析的时候,有可能获取的是整个字符串,此时可能就会出现BYPASS。

multipart data

Multipart/form-data的请求方式来完成上传图片等服务器交互的操作,这需要我们去严格按照规范的格式来组装请求体,每一个换行每一个空格都是不可忽略的。

Multipart/form-data的基础方法是POST,也就是说是由POST方法来组合实现的

Multipart/form-data与POST方法的不同之处在于请求头和请求体

  • Multipart/form-data的请求头必须包含一个特殊的头信息:Content-Type
    • Content-Type的值必须规定为multipart/form-data
    • 同时还需要规定一个内容分割符用于分割请求体中的多个POST的内容,如文件内容和文本内容自然需要分割开来,不然接收方就无法正常解析和还原这个文件了
  • Multipart/form-data的请求体也是一个字符串,不过和post的请求体不同的是它的构造方式
    • post是简单的name=value值连接
    • Multipart/form-data则是添加了分隔符等内容的构造体

请求的头部信息如下

Content-Type: multipart/form-data; boundary=你的自定义boundary

boundary这个参数是分界线的意思,也就是说你在请求头中指定分界线为:你的自定义boundary,那么请求体中凡是你的自定义boundary这样的字段都会被视为分界线,这个分界线参数具体是什么你可以随意自定义

实例

只识别了两个分隔符,中间的内容都成为了内容,php在解析分隔符时会自动忽略,之后的内容正常解析请求,然而某些waf会把这数个content-disposition识别为一整串内容,从而达到bypass的效果。

iis
%特性

在asp+iis的环境中存在一个特性,就是特殊符号%,在该环境下当们我输入s%elect的时候,在WAF层可能解析出来的结果就是s%elect,但是在iis+asp的环境的时候,解析出来的结果为select

本地搭建asp+iis环境测试

1. 在实体机或是虚拟机中安装iis+asp环境

2. 随后我们在存放本地页面的文件夹中创建一个名为index.asp的文件

用记事本打开后输入以下内容并保存:

<form method="get"action="simpleform.asp">
<p>First Name:<input type="text" name="fname"/></p>
<p>Last Name:<input type="text" name="Iname"/></p>
<input type="submit"value="Submit"/>
</form>

3. 创建第二个新的名为simpleform.asp的文件:

<body>
Welcome
<%
response.write(request.querystring("fname"))
response.write(" " & request.querystring("Iname"))
%>
</body>

4. 打开浏览器在地址栏输入localhost:8099/index.asp

注意:此处的端口号按照你分配给的端口号为准。

我们可以看到一个简单的submit框

分别输入:

  • wa%sj
  • inc

随后点击submit

页面显示

此时URL中%转码为了%25

如果URL中改成%,则会显示

这就是iis环境中的%特性,我们可以依次这个特性构造诸如sel@ect的语句利用waf与iis服务器解析的差异达到bypass效果

u%特性

iis服务器支持对于unicode的解析,例如我们对于select中的字符进行unicode编码可以得到s%u006c%u0006ect,这种字符在IIS接收到之后会被转换为select,但是对于WAF层,可能接收到的内容还是s%u006cu0006ect,这样就会形成bypass的可能。

本地搭建asp+iis环境测试

在index.asp页面我们分别输入以下内容:

  • s%u0065%u006cect
  • select

提交后页面显示

此时URL中%也转码为了%25

如果URL中改成%,则会显示

另类%u特性

该漏洞主要利用的是unicode在iis解析之后会被转换成multibyte,但是转换的过程中可能出现:多个widechar会有可能转换为同一个字符。

打个比方就是譬如select中的e对应的unicode为%u0065,但是%u00f0同样会被转换成为e。

  • s%u0065lect->select
  • s%u00f0lect->select

WAF层可能能识别s%u0065lect的形式,但是很有可能识别不了s%u00f0lect的形式。

这样就可以利用起来做WAF的绕过

Web应用层绕过

双重url编码

双重url编码,即对于浏览器发送的数据进行了两次urlencode操作,如s做一次url编码是%73,再进行一次编码是%25%37%33

一般情况下数据经过WAF设备的时候只会做一次url解码,这样解码之后的数据一般不会匹配到规则,达到了bypass的效果

nginx url解码问题带来的waf绕过漏洞

nginx的ngx_unescape_uri函数在处理url decode时没有遵照标准的url decode,从而引起一系列使用该函数解码的waf都存在绕过漏洞。

出现该问题的函数位于src\core\ngx_string.c代码中ngx unescape_uri(u_char **dst, u_char*src, size_t size, ngx_uint_t type)该函数在处理%号编码时,如果%后面第一个字符非16进制范围则会丢弃%,否则第二个字符非16进制范围则会丢弃%和第一个字符

具体表现为SQL注入关键字select如果写成s%elect经过ngx编码处理后则会变成slect从而绕过waf过滤规则,例如lIS asp对s%elect的编码处理结果为select,还有and经过ngx解码函数后会变为nd等等。

请求获取方式
变更请求方式
GET,POST,COOKIE

在web环境下有时候会出现统一参数获取的情况,主要目的就是对于获取的参数进行统一过滤。

例如我获取的参数t=select 1 from 2这个参数可以从get参数中获取,可以从post参数获取,也可以从cookie参数中获取。

典型的案例是dedecms,在之前测试的时候就发现了有些waf厂商进行过滤的时候过滤了get和post,但是cookie没有过滤,直接更改cookie参数提交payload,即绕过。

使用bp可以进行请求方式的切换

urlencodeform-data POST

在提交数据的时候有两种方式

  • urlencode
  • form-data

当我们在测试站点的时候,如果发现POST提交的数据被过滤掉了,此时可以考虑使用form-data的方式去提交

使用bp可以进行两种格式的切换

asp/asp.net request解析

在asp和asp.net中使用参数获取用户的提交的参数,一般使用request包,譬如使用request['']来获取的时候可能就会出现问题。

当使用request['']的形式获取包的时候,会出现GET、POST分不清的情况

譬如可以构造一个请求包,METHOD为GET,但是包中还带有POST的内容和POST的content-type

HPP

HPP是指HTTP参数污染。形如以下形式:

?id=1&id=2&id=3的形式,此种形式在获取id值的时候不同的web技术获取的值是不一样的。

假设提交的参数即为:

id=1&id=2&id=3

  • Asp.net iis:id=1,2,3
  • Asp iis:id=1,2,3
  • Php apache:id=3

如此可以分析:当WAF获取参数的形式与WEB程序获取参数的形式不一致的时候就可能出现WAF bypass的可能。

此处关键还是要分析WAF对于获取参数的方式是如何处理的

hpp可以灵活运用,譬如有些cms基于url的白名单,因此可以利用hpp的方式在参数1的位置添加白名单目录,参数2的位置添加恶意的payload。比如:

index.php?a=[whitelist]&a=select 1 union select 2

数据库层bypass

数据库层bypass常常是在bypass waf的sql注入防护规则。我们需耍针对数据库,使用该数据库的特性即可。如mysql,sqlserver等等。

目前数据库被暴露出来的特性很多很多,基本上很多特性综合利用就已经够用了,因此特性知不知道是一方面,能不能灵活运用就 得看测试者自己

mysql数据库

就目前来看是使用最多的,也是研究人员研究最深的数据库。测试的角度上一般会测试下面的过滤点,因为一般绕过了select from就基本可以sql注入获取数据了。

常见过滤位置
参数和union之间的位置
  • \Nunion

  • 浮点数,如8.0

  • 8e0

  • /*!50000*/

union和select之间的位置
  • 空白字符 mysql中可利用空白字符有%09%0a%0b%0c%0d%a0
  • 空白注释 mysql中可利用空白注释有/**//*letmetest*/
  • 使用括号

常见过滤函数
字符串截取函数
  • Mid(version(),1,1)
  • Substr(version(),1,1)
  • Substring(version(),1,1)
  • Lpad(version(),1,1)
  • Rpad(version(),1,1)
  • Left(version(),1)
  • reverse(right(reverse(version()),1))
字符串连接函数
  • concat(version(),'|',user());
  • concat_ws('|',1,2,3);
字符转换

Ascii(1)此函数之前测试某云waf的时候被过滤了,然后使用ascii(1)即可

  • Char(49)
  • Hex('a')
  • Unhex(61)
过滤了逗号
  • limit处的逗号,通过limit 1 offset 1绕过

  • 字符串截取处的逗号,比如mid处的逗号,通过mid(version() from 1 for 10)绕过

  • union处的逗号,通过join拼接绕过

sqlserver数据库
常见过滤位置
select from后的位置
  • 可以通过空白字符绕过
    • 01~0F10~1F20都是空白字符
    • 需要做urlencode salserver中的表示空白字符比较多,靠黑名单去阻断一般不合适
  • 注释符号Mssql也可以使用注释符号/**/
  • 其他符号:.符号

select from后之间的位置
  • 可以通过空白字符绕过
    • 01~0F10~1F20都是空白字符
    • 需要做urlencode salserver中的表示空白字符比较多,靠黑名单去阻断一般不合适
  • 注释符号Mssql也可以使用注释符号/**/

  • 2017版本之前还可以通过:绕过
and之后的位置
  • 可以通过空白字符绕过
    • 01~0F10~1F20都是空白字符
    • 需要做urlencode salserver中的表示空白字符比较多,靠黑名单去阻断一般不合适
  • 注释符号Mssql也可以使用注释符号/**/
  • 2017版本之前还可以通过:绕过
常见过滤函数
字符串截取函数
  • Substring(@@version,1,1)
  • Left(@@version,1)
  • Right(@@version,1)
字符串转换数

Ascii('a')这里的函数可以在括号之间添加空格的,一些waf过滤不严会导致bypass

Char('97')

其他方式

Mssql支持多语句查询,因此可以使用;结束上面的查询语句,然后执行自己构造的动态执行。

  • 使用exec的方式构造语句使返回查询结果的时间向后延迟五秒钟

  • 使用sp_executesql的方式构造语句使返回查询结果的时间向后延迟五秒钟

WAF层绕过

性能bypass

WAF在设计的时候都会考虑到性能问题,例如

  • 如果是基于数据包的话会考虑检测数据包的包长
  • 如果是基于数据流的话就会考虑检测一条数据流的多少个字节

一般这类算检测的性能,同时为了保证WAF的正常运行,往往还会做一个bypass设计,在性能如cpy高于80%或则内存使用率高于如80%是时候,会做检测bypass,以保证设备的正常运行。

WAF等设备都是工作在应用层之上的,如HTTP、FTP、SMTP等都是应用层的协议,这些数据要被处理都会被进行数据解析,协议分析。最终获取应用层的数据。如HTTP的方法是什么,HTTP的querystring是什么,以及HTTP的requestboody是什么。然后将这些实时获取的值与WAF设计的规则进行匹配,匹配上着命中规则做相应的处理。

性能检测bypass

现在问题就是检测多长呢?

例如我用HTTP POST上传一个2G的文件,明显不可能2G全做检测,不但耗CPU同时也会耗内存。

因此在设计WAF的时候可能就会设计一个默认值,有可能是默认多少个字节的流大小,可能是多少个数据包。

测试实例

测试安全狗的,大致原理应该是通过一个脚本,不断的向HTTP POST添加填充数据,当将填充数据添加到一定数目之后,发现POST中的注入恶意代码没有被检测了。

最终达到了bypass的目的。

在测试某家云WAF的时候使用此类方法也可以达到bypass的目的。

性能负载bypass

一些传统硬件防护设备为了避免在高负载的时侯影响用户体验,如延时等等问题,会考虑在高负载的时候bypass掉自己的防护功能,等到设备的负载低于门限值的时候又恢复正常工作。

一些高性能的WAF可能使用这种方法可能不能bypass,但是一些软WAF使用这种方式还是可以bypass的。

测试实例

一个bypass的例子,将请求并发同时发送多次,多次访问的时候就有几次漏掉了,没有触发waf的拦截。

例如制造了一个payload,同时添加了大量的无效数据,使用脚本发送该请求,发现请求的时候有些通过了WAF,有些被WAF所拦截了。应该就是性能问题导致了bypass。

fuzz bypass

使用脚本去探测WAF设备对于字符处理是否有异常,上面已经说过WAF在接收到网络数据之后会做相应的数据包解析,一些WAF可能由于自身的解析问题,对于某些字符解析出错,造成全局的bypass。

我测试的时候常常测试的位置:

  • get请求处
  • header请求处
  • post urlencode内容处
  • post form-data内容处

然后模糊测试的基础内容有:

  • 编码过的0-255字符
  • 进行编码的0-255字符
  • utf gbk字符
测试实例

在一次测试安全狗的过程中,使用POST的方式提交数据,提交数据包括两个参数

  • 正常的fuzz点
  • 一个参数包含一个Sql注入语句

当在测试前面的fuzz点的时候,处理到\x00的字符时,没有提示安全狗阻拦。应该是解析这个字符的时候不当,导致了bypass。

在一次测试云WAF中,使用get方式提交数据,提交内容包括一个参数,参数为字符+sql注入的语句。当在fuzz字符的时候,发现云waf在处理到&字符的时候,没有提示云waf阻拦。

由于&字符的特殊性,猜测是由于和请求中的&没有处理好导致的

由于mysal中&&同样可以表示and,因此拼凑一下sql语句就达到了bypass的目的。

白名单bypass

WAF在设计之初一般都会考虑白名单功能。

如来自管理IP的访问,来自cd如服务器的访问等等。这些请求是可信任的,不必走WAF检测流程。

  • 获取白名单的IP地址如果是从网络层获取的IP,这种一般bypass不了
  • 如果采用应用层的数据作为白名单,这样就可能造成bypass

之前有一篇文章内容是通过修改http的header来bypass waf,这里我们截取文章中部分内容:

这些header常常用来获取IP,可能还有其他的,例如nginx-lua-waf

获取clientip使用了X-Real-ip的header

此种方法还可以用来绕过如登陆锁IP,登陆多次验证码,后台验证等等的场景

http://www.lryc.cn/news/604635.html

相关文章:

  • KONG API Gateway中的核心概念
  • 聊聊如何判断发现的缺陷属于前后端
  • 【Dolphinscheduler】docker搭建dolphinscheduler集群并与安全的CDH集成
  • winsock socket通讯为什么UDP服务器无法获取客户端IP?
  • UDP通讯和TCP通讯的区别-UDP(用户数据报协议)和 TCP(传输控制协议)
  • BeeWorks Meet:私有化部署,重塑高安全需求行业的视频会议体验
  • 云计算:一场关于“数字水电煤”的革命与未来
  • LoongCollector 安全日志接入实践:企业级防火墙场景的日志标准化采集
  • java~单例设计模式
  • react19更新哪些东西
  • 如何通过IT-Tools与CPolar构建无缝开发通道?
  • 第十七章 追新词
  • 7.Linux :进程管理,进程控制与计划任务
  • LLM—— 基于 MCP 协议(Streamable HTTP 模式)的工具调用实践
  • 【拓扑排序】P2403 [SDOI2010] 所驼门王的宝藏|省选-
  • Redis学习------缓存雪崩
  • 01初识算法:从零开始的思维之旅
  • 【Spring Cloud】Spring Cloud 跨域解决方案深度剖析与工程实践指南(万字详解)
  • docker 安装elasticsearch
  • uniapp中的$vm
  • LeetCode 56 - 合并区间
  • 7. 传输层协议 TCP
  • 关系型数据库架构最优选择:基于落霞归雁思维框架的分析
  • 15.11 单卡训练770M参数模型!DeepSpeed ZeRO-3实战:RTX 4090显存直降6.8GB
  • 10 分钟上手 Elasticsearch 语义搜索(Serverless Cloud 本地双版本教程)
  • 基因组选择育种-2.1.最佳线性无偏估计
  • GitHub使用小记——本地推送、外部拉取和分支重命名
  • RPA软件推荐:提升企业自动化效率
  • STM32学习记录--Day3
  • IPEmotion数据采集软件功能介绍