# 【由浅入深_打牢基础】WEB缓存投毒(上)
【由浅入深_打牢基础】WEB缓存投毒(上)
1. 什么是WEB缓存投毒
简单的来说,就是利用缓存将有害的HTTP响应提供给用户
什么是缓存,这里借用Burp官方的一张图来说,就是当一个用户去发起一个请求的时候,会经过缓存,但是缓存中如果不存在的话,后端才会响应并将其添加到缓存,之后的用户如果发送等效请求的话,会直接从缓存中获取。
image-20220608170226090如上所说,那么后端怎么判断我们两个用户的请求是等效的呢?
这里我们要知道一个东西叫缓存键(cache key),预先定义的请求头中的一些键作为缓存键,只要这些缓存键的值一样后端就认为两个包是等效的,那么头部的其它键就称为非缓键了
==所以==我们web缓存投毒都依赖于非缓存键(因为缓存键是后端判断我们请求是否等效的,所以通常情况下不能改变,也就不能payload,不然的话跟其它用户就不等效,就无法投毒),缓存投毒的另外一个条件就是,页面存在某个内容是根据非缓存键的值来生成的。
#例如存在非缓键X-Forwarded-Host,而页面存在一个a标签,它的href是根据X-Forwarded-Host来生成的
#正常请求
GET / HTTP/1.1
Host: test.com
X-Forwarded-Host: www.demo.com
#正常响应
<a href='www.demo.com'></a>
#我们就可以利用web投毒构造XSS
GET / HTTP/1.1
Host: test.com
X-Forwarded-Host: #'></a><script>alert(1)</script> //
#响应变成了
<a href='#'></a><script>alert(1)</script> // '></a>
当我们利用的时候,找到一个非缓存键并且它的值会影响网页响应包就变得很重要,我们可以使用Burp上的插件Param Miner
,它在Burp商店中就可以找到
2. 漏洞利用
微信公众号:小惜渗透,欢迎大佬一起交流进步
我这里根据Burp的实验室来展示WEB缓存投毒的利用方式
2.1 带有未键标头的 Web 缓存中毒
要求:
image-20220608220926830利用过程:
首先我们通过Param Miner
插件来获取对网页有影响的非缓存键,右键请求包,然后选Guess headers
,然后用默认设置即可,点ok
可以看到,找到了x-forwarded-host
(XFF标头用来体现请求所经过的代理服务器,而XFH用来体现用户最初访问的HOST)
紧接着我们去发包测试下(注意大小写),这里主要我们要在请求上随便加个参数,防止我们这个测试的请求被缓存
image-20220608221926250注意这里X-Cache
为miss
,证明没有命中缓存。
但是当我们迅速再发一次包,证明是从缓存中获取的响应
image-20220608222356586所以们去漏洞利用服务器构造js文件
image-20220609152156320主页这里有很多商品,我们随便挑一个进行投毒
image-20220609152308705紧接着正常访问这个页面,这里没有cookie是正常的,因为在set-cookie的时候,加上了HttpOnly
image-20220609155046426但是并没有通过的提示,最后一顿搞,发现你不能投毒其它产品界面,必须投毒根页面,醉了
image-202206091549541072.2 使用未键入的 cookie 进行 Web 缓存中毒
要求:
image-20220609155457201利用过程:
看题意,cookie不是非缓存键,那么就要在cookie上做文章了,抓包看一下值,这里有一个fehost
参数,我将它的值改成like,果然在响应包中发现了它
接下来我们就可以构造payload了,进行投毒了
fehost=someString"%2Balert(1)%2B"someString
image-20220609163349036
然后我们去访问(同样要在根目录投毒)
image-202206091635412722.3 具有多个标头的 Web 缓存中毒
要求:
image-20220609163626834利用过程:
根据提示可知,这次存在多个非缓存键,并且要一起利用才行,所以这里用Burp的Param Miner
插件去探测标头,这里发现了X-Forwarded-Scheme
(它的作用就是体现通信的协议是http还是https的)
那么还差一个头,因为标题说需要两个标头,所以我猜大概率还是之前的X-Forwarded-Host
,接下来验证猜想,我先手动加上X-Forwarded-Host
头尝试一下
那么我改成我们探测到的X-Forwarded-Scheme
还是不行,那么我两个头都加上,神奇的事情发生了,重定向了,不过定向的地址是我们填的test.com
,接下来思路就来了,我们让其定向到一个能能控制js代码的页面不就完了
于是我想起了,实验室为我们准备的漏洞利用服务器,但是它构造的body只能是文字,所以我尝试将其改成html后缀结尾但是也不可以
image-20220609213859150 image-20220609213944772这个时候我突然想到我们之前的做法,我们的主页是会加载js文件的,我们只要让它加载的js文件变成我们的就好了,于是我尝试在js文件上投毒,主页加载了/resources/js/tracking.js
的js文件,所以我们找到这个包,然后尝试投毒,先构造js
紧接着在js请求上投毒
image-20220609215126520再次访问主页,成功啦
image-202206092152395312.4 使用未知标头的有针对性的 Web 缓存中毒
要求:
image-20220610145641760利用过程:
首先我们还是检测一下非缓存建,发现X-Host
然后我们带上X-Host
来发送一下,这里注意看到返回包有根据X-Host去加载js,但是看到返回包的Vary(这个头代表缓存建)里面带User-Agent
,也就表名了UA头是缓存键,也就表示我们投毒的时候,下一个包必须跟我们投毒的包的UA头一样才能触发缓存,
所以想达投毒目标,我们需要找到用户的UA头,然后根据他们的UA头去投毒,然后发现我们评论竟然支持html代码,这样的话思路就来了,我们可以写一个图片标签,地址是我们的漏洞利用服务器,然后当用户访问了这个留言板就会去发请求获取我们的发的图片标签,然后就会请求到我们的利用服务器,最后我们自然可以通过日志查看到他的UA
image-20220610152203216然后查看UA
image-20220610152230291紧接着构造JS文件
image-20220610151438896主页投毒
image-20220610152336553静静等几秒
image-202206101523525862.5 通过无键查询字符串导致 Web 缓存中毒
要求:
image-20220610155355025利用过程:
发现可以根据参数构造XSS
image-20220610161404884 image-20220610161448706那么我们如何投毒呢?很简单,我发现改变参数和值并不会领缓存失效,换言之此页面的参数不是缓存键,所以不管我们参数改成什么生成的缓存仍然是主页的
image-20220610161603342成功投毒
image-202206101615131452.6 通过未键入查询参数的 Web 缓存中毒
要求:
image-20220610161821371利用过程:
看说明表示排除了个参数,所以我们可以用插件跑,不过这次不是跑header了而是跑参数
image-20220610173058807然后我们研究一下这个包,第一次如下传了个参数abc
image-20220610173715997立马发第二个包,把参数加个1,这里我们发现参数算作了缓存键,那这样的话就完bk了,因为这样的话必须我们传参,并且用户访问的时候跟我们传相同的参数才能命中缓存,所以再看下要求,证明这里面肯定有某个参数给排除在外了,那它就是我们需要依赖的非缓存键了
image-20220610173806731于是乎我们等待着插件给我们跑结果过,大概过了一万年后,跑出来了
image-20220610175833122==补充:==这里补充一下,UTM
(统一威胁管理):即将防病毒、入侵检测和防火墙安全设备划归统一威胁管理。所以可能网站会发送很多日志分析包包给UTM,所以发送给UTM的参数是肯定不能作为缓存键的(因为你给威胁管理平台发送的肯定是实时的最新的数据,以便侦测威胁,所以肯定不能给相关参数算作缓存键)。
既然如此那就直接投毒吧
image-20220610205044599通过
image-202206102050544782.7 参数隐藏
要求:
image-20220610214925844利用过程:
这个说真的,发现起来有点难啊,所以我尽量从一个发现者的角度来分析发现这种漏洞的思路,首先当我们访问主页发现响应包有X-Cache
说明网站存在缓存机制,浏览一下其它的包,发现有一个js文件的请求,而且重点是后边还有个参数
那我们观察一下它,发现js响应内容和我们传的参数值相同,那么我们可以尝试改一下值
image-20220610222115010我在值后边多加一个1,如下图,果然响应包存在跟随其变化的内容
image-20220610222233166但是因为我这两个包是连着发的,所以证明参数作为了缓存键,当我们第二个包改变值的时候发现没有命中第一个包的缓存,所以这里就很矛盾,例如我们修改值为alert(1),可以构造xss但是不能成功缓存(因为其它用户在访问的时候值肯定都是setCountryCookie),所以这时候就可以尝试多参数,如下图加了个分号紧接着又传相同参数但值不同(当我们挖掘漏洞的时候也需要尝试这种思路,例如短信验证码,可以尝试原本手机号后边加逗号然后再跟一个手机号)
image-20220610222955203这样的话其实又存在一个问题,那就是它仍然不能让普通用户命中缓存如下图
image-20220610223453792 image-20220610223457106上边两张图可以看出,两个包并不算等效请求,为什么?其实看参数的颜色就能看出来,第一个包从分号开始都算作了第一个callback的值,它跟第二个包的值不同所以当然不算了,那怎么办呢?还记得我们上一个实验室的utm_content
,我们可以测试一下它是否还是非缓存键,如果是那就好办了(当然实战的时候还是可以用插件猜参数,不过插件执行的这个时间着实有点长)
第一个包如下,我将callback参数改成了test,当然响应肯定存在test了,不过我在参数后边又加了一个utm_content
,值随便写,这时候X-Cache
为miss状态
我随即发出了第二个包如下,callback
的参数依旧是test,不过后边我没写utm_content
参数,但是我们发现它依然是命中了上一个包的缓存,也就证明utm_content
非缓存键(准确的说我感觉应该叫它非缓存参数)
好了,那证明出来了有什么用呢?这个时候就可以根据以上信息进行投毒了,看下边的数据包,首先第一个callback的值是初始的setCountryCookie也就是跟其它用户一样的,紧接着我们加了utm_content
,由于它是非缓存参数所以不会影响我们投毒,然后后边我们又跟了个;callback=alert(1)
,这是为了让我们的响应包构造出XSS,但是它也是对我们投毒没影响的,因为它算在了utm_content
参数的值内,so,大功告成了
==注意:==如果想让我们的请求不命中缓存,除了等待缓存失效外还可以添加下边这个两个header
image-20220610230944471ok就到这里了,剩下的WEB缓存投毒等后续再研究,下次我会转载一个之前看到的,类似的挖掘实战贴。