0%

ProxyPoolxSocksFofa-hack配合自建代理池

两个工具

Anyyy111/ProxyPoolxSocks: ☁️Socks代理池服务端自动化搭建工具☁️ (github.com)

Cl0udG0d/Fofa-hack: 非付费会员,fofa数据采集工具 (github.com)

这两天项目天天封我ip,草,他还是一堆域名一起封禁的,我整个公司的站都进不去了。电脑上的全局代理工具也代理不了burp,Proxifier虽然可以代理burp但是我没有那么多代理啊,所以决定研究一下代理池。

先抓代理

抓代理,很简单,给一个fofa语法先

protocol=="socks5" && "Version:5 Method:No Authentication(0x00)" && after="2023-11-23" && country="CN"

然后用fofahack来抓代理

1
2
fofa-hack.exe --keyword "protocol=='socks5' && 'Version:5 Method:No Authentication(0x00)' && after='2023-11-23' && country='CN'" --authorization "fofatoken"
--endcount 5000 --output OUTPUT --timesleep 2

这里贴一下参数吧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
-h, --help            show this help message and exit
--keyword KEYWORD, -k KEYWORD
fofa搜索关键字
--inputfile INPUTFILE, -i INPUTFILE
指定文件,从文件中批量读取fofa语法
--base BASE, -b BASE 以base64的形式输入关键字 -b InRoaW5rcGhwIg==
--timesleep TIMESLEEP, -t TIMESLEEP
爬取每一页等待秒数,防止IP被Ban,默认为3
--timeout TIMEOUT, -to TIMEOUT
爬取每一页的超时时间,默认为180秒
--endcount ENDCOUNT, -e ENDCOUNT
爬取结束数量
--level LEVEL, -l LEVEL
爬取等级: 1-3 ,数字越大内容越详细,默认为 1
--output OUTPUT, -o OUTPUT
输出格式:txt、json,默认为txt
--outputname OUTPUT, -on OUTPUTNAME
指定输出文件名,默认为fofaHack
--fuzz, -f 关键字fuzz参数,增加内容获取粒度
--proxy PROXY 指定代理,代理格式 --proxy '127.0.0.1:7890'
--authorization AUTHORIZATION
指定Authorization值

image-20240223235634246

好,反正现在已经抓下来了。准备搭建代理池

搭建代理池

服务端

先去下一下吧Anyyy111/ProxyPoolxSocks: ☁️Socks代理池服务端自动化搭建工具☁️ (github.com)

然后这个分为服务端和客户端,我们这里把服务端搭建在vps上面,

这里的代理前面需要加一个socks://,我这里写了个py脚本,来批量让抓取的代理地址前面加上这个文本,脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 读取原始txt文件
with open('fofaHack.txt', 'r') as file:
lines = file.readlines()

# 处理每一行,添加"socks://"
new_lines = ['socks://' + line.strip() for line in lines]

# 将处理后的内容写入新的txt文件
with open('output_file.txt', 'w') as file:
file.write('\n'.join(new_lines))

print("处理完成,请查看output_file.txt文件。")

image-20240224000441767

代理池从github下载下来之后,直接传到vps上面,然后里面的node.txt文件里面填写我们刚刚弄的代理地址。

我草我服了,这也能报错啊,
image-20240224001016240
这里我弄了三千多个节点进去,然后报错了,待我把代码放本地来调试一下。。。。

好,改好了,把当前文件夹下面的都getaddress.py的第51行代码改成如下内容

1
2
3
4
5
6
7
8
9
10
try:
parts = node.split('socks://')[1].split(':')
if len(parts) >= 2:
addr, port = parts[:2]
# 执行接下来的操作
else:
print("无法正确解析地址和端口")
except IndexError:
print("无法正确解析地址和端口")

image-20240224002514322
改成这样
image-20240224002524734

这样就好了,现在我们把vps上面的服务端搭建起来

直接python run.py,注意必须要python3.7版本已上。。这centos yum下载的是2的版本,要改版本可以参考此博客
centos7安装python3.7 - Mr_Yun - 博客园 (cnblogs.com)
又改了一万年

然后直接运行run.py就行
image-20240224010141686

好力!

客户端

可以在文件夹Client-check里面的client.py来检测一下可用性

或者直接用proxifier即可。但是很多抓取到的ip其实是不能用的,不过夜无所谓,这样就好了。

钓鱼基础

今天来说说钓鱼方面的内容

身份方面

有一下几种平台的
微信,qq,脉脉,boss,领英,猎聘,智联

小tips:
1.微信号不要买黑号
2.脉脉在授权的情况下,最好用自己的身份证注册
3.脉脉可以用一些大厂的工牌,ps后来认证。(也就是说,那上面的hr也可能是别人伪造的)
4.微信注册的号,也可以自己来注册一些号来养着。

hr

这里比如你有一个hr的账号了,就是伪造的hr账号嘛,然后话术之类的:
1.你好,请问你最近在看机会吗?xxx公司有一个不错的岗位,可以聊聊吗?随后让对方添加微信或这其他聊天方式进行诱导。

然后需要准备的资料
1.手机小号
2.注册微信,猎聘等平台(微信需要绑定银行卡,否则会报身份可疑
3.工牌,名片
4.身份证正反面,手持省份证

套路

脉脉

1.确定目标企业,开通会员
2.批量申请添加好友,探测是否有求职意向,再针对性做JD(招聘要求),发送钓鱼样本
3.话术引流至微信

领英

1.无需实名及职业认真,不过领英偏外国一点

话术

已异性,求职,助人为突破口

大多邮件格式都是通过目标公司来修改的,可以在网上找一找目标公司的通知。

1
2
3
4
由于咱们目前公司正在进行xxx攻防演练,然后给一个“补丁”

后面可以加一个:
补丁安装中,可能会报毒,大家点击信任即可
1
还有,如果打到的内网机器有类似“内网通”的功能,可以通过这个来进行扩展
1
冒充学生给老师或者给同学发文章
1
由于远程办公,安装vpn
1
发现公司内部存在恶意病毒文件传播,需要安装测试脚本进行排查
1
同时也可以通过二维码来进行钓鱼,就类似于早年间那种盗qq邮箱的钓鱼网页

敏感数据收集

比如要社工某个目标人员,我们可以通过以下几个方面来进行搜集钓鱼的邮箱和人员信息

寻找目标服务器地址

1
通过域名 MX 记录 寻找邮件服务器;MX 服务器通C段寻找WEB邮件入口(25 109 110 143 456 995 993端口);域名扩展寻找web部件服务器入口,获取邮件系统供应商(MAIL OWA);收集SPF、DMARC开放策略

可以通过dig命令寻找,dig出来的server,大多就是服务器地址,然后就是一些dns记录

批量收集邮箱的信息

1
2
3
比如说通过领英等社交网站拿到邮箱,然后就可以进行钓鱼,撞库等等操作,工具可以用
https://github.com/DisK0nn3cT/linkedin-gatherer
可以针对某个特定域名,生成excel,包括姓名,邮箱,职位,照片,也可以只输入名字,定向搜索某人。

同时也可以直接在百度,谷歌里面搜对面公司邮箱的后缀名,然后来进行搜集

github搜索

可以通过对面公司的后缀名啊,关键词啊来进行搜索。
这里推荐一个github搜索的引擎。https://cs.github.com
这个是官方的

hunter.io

这个也是个专门收集邮箱的网站,完整使用功能需要注册,且普通用户使用还有次数限制

https://hunter.io

Mailget

Ridter/Mailget: 通过脉脉用户猜测企业邮箱 (github.com)

通过上方收集到一些邮箱分析生成字典

比如说用常用的人名更具手机来的邮箱分析生成

在线网站收缩

https://souyouxiang.com

脉脉

TG的SGK

获取合法邮箱

获取合法邮箱途径可以通过借助登陆窗口密码找回功能漏洞挖掘、验证码绕过,问题答案绕过、问题答案可爆破、邮箱撞库、密码爆破、邮箱爆破、协议爆棚、OWA爆破、接口爆破等方式。

弱口令爆破,适用于目标企业自己的邮箱服务器如OWA等,想百度腾讯阿里网易的邮箱不优先考虑。

工具可以使用Medusa、Hydra、SNETCracker、OWA爆破、exchange接口爆破等工具。另外邮箱用户名与密码往往还会使用公司简称+2019、2020等社工口令,多一个字典就多一份成功率

诱饵制作

木马生成

这个本宝宝即将是免杀大神,不用管!(maybe😋

传输加密附件

通过附件加密,可绕过安全设备检测,从而讲恶意附件投递至收件人邮箱,对压缩文件进行加密,密码以其他方式告知受害者。
因为主流的一些公司,他们的邮箱服务器是装了沙箱的,所以你传递的木马必须要加密,否则会被解压。
密码告知方式可以用以下方式

1
2
3
4
1.用图片或者pdf形式告知
2.补发一份无附件的邮件来告知
3.在正文中进行简单的文字混淆,比如说繁体字或者符号
4.社工目标账户,通过微信等方式告知

快捷方式(link)

我们可以利用attrib命令将我们的木马与伪装文件隐藏

1
2
attrib muma.exe +s +h
attrib wenjian.docx +s +h

这个命令
image-20240218010616903

同时我们也可以将快捷方式中的目标栏内容改成执行powershell命令远程下载木马并且运行。不过调用powershell不太好,所以不推荐

利用恶意文件、利用命名、图标伪装的快捷方式诱导点击,将真实要执行的恶意文件进行隐藏

创建快捷方式指向该文件,修改目标内容为explorer.exe .\1.exe这个explorer是windows自带的执行exe的东西,而且还不会弹窗,不过一次只能执行一个exe
值得注意的是,快捷方式可以更改后缀名,所以非常方便

编码文件后缀欺骗

这个我之前写过博客啊RLO编码,这个会触发大多杀软的,也只能用来骗骗小白。

自解压

利用winrar压缩工具自带的自解压功能实现全程无感知上线
winrara:https://rarlab.com
resourcehacker:https://www.angusj.com/resourcehacker

首先要准备一个安装包和一个cs的木马,利用工具resourcehacker来修改木马的内容即可,这个可以在网上找教程,或者我后续会出文章来复现(至于为什么现在不复现,因为看视频的时候会把电脑的复制键给禁掉)

然后就可以把两个正常的东西弄成一个自解压的压缩文件,这里值得注意的是,在高级设置里面,点击常规,然后设置解压路径%temp%,并勾选绝对路径,然后点击旁边的设置,找到提取后运行设置好两个文件都要允许,模式选择全部隐藏更新方式选择解压并替换文件覆盖方式选择覆盖所有文件,而且还可以改文件的时间。

后续我专门出一片来复现一下算了,这个不复现不行啊。

钓鱼邮件伪造

SPF

这个方法,如果批量的话,可能被封ip,用下面的aliyun的批量就不会,

sender polict framework的缩写,一种以IP地址认证电子邮件发送人身的技术,是非常搞笑的垃圾邮件解决方案.接受邮件方会首先检查域名的SPF记录,来确定发件人的IP地址是否被包含在SPF记录里面,如果在,就认为是一封正确的邮件,否则会认为是一封伪造的邮件进行退回。

正常的邮箱SPF设置是TXT记录值为:v=spf1 include:spf.mail.qq.com -all
然后我们看我们的攻击的点设置是-all,这是一条错误的配置方法。

小tip:Outlook可以批量发邮件,但是发送人会被看到,所以就引出了一个SPF伪造的方法。

可以使用swaks来进行伪造(要企业没有做spf)

1
2
3
4
5
swaks --to xxxxx@qq.com --from ahztrust@kmpex.com --ehlo hztrust.com --body 111 --heade-X-Mailer mail.baidu.com 
to参数是发送的目标
from是伪造的地址,没做spf的
ehlo是邮件里面的的东西
header也设置成

这里可以用dig命令看看对方的服务器做了spf校验没有
dig命令是可以从dns域名服务器去查询主机地址信息

但是有些公司的子域名是没有所spf校验的,例如qq.com做了,但是mail.qq.com没做

1
dig -t txt qq.com

值得注意的是,dig命令不是linux自己集成的,需要重新下载

值得注意的第二点,163也许不会拦截接收到伪造的邮件,但是有些邮件网关会杀掉。

邮件代发

https://www.winmail.cn/

可以利用这个平台进行搭建即可批量发送,不过需要一个服务器来搭建
不过很多团队都有自己的邮件平台,我们这种小东西就只能自己搭建哩

利用阿里云邮件推送免费发邮件

每天免费200封,速度快不用搭建服务器,量多可以花钱

https://dm.console.aliyun.com

不过需要自己去申请一个域名,可以用国外的免费域名,不用备案。
找一个和目标客户相似的域名就行。

同时淘宝也可以申请

阿里云貌似也可以用刚刚那个工具swaks来代发,这个得自己研究一下。

然后可以直接在163上面直接写邮件,然后导出邮件,导出之后就可以直接用swaks,用–data参数来直接用,不过记得修改发件人和收件人

shiro权限绕过方面漏洞分析

今天来学习权限绕过方面的漏洞,都尽量复现一遍,然后分析分析,我们这里用vulhub靶场吧…

Apache Shiro -目录遍历漏洞 CVE-2010-3863

漏洞信息

漏洞编号:CVE-2010-3863 / CNVD-2010-2715
影响版本:shiro < 1.1.0JSecurity 0.9.x
漏洞描述:Shiro进行权限验证前未进行路径标准化,导致使用时可能绕过权限校验
漏洞补丁:Commit

漏洞分析

先分析一下Shiro身份验证的流程:Shiro使用org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver#getChain 方法获取和调用要执行的 Filter,逻辑如下:
getPathWithinApplication()方法中调用 WebUtils.getPathWithinApplication()方法,用来获取请求路径。
其中getContextPath(request)方法获取 Context 路径(这里这个context可以理解为,当前路径)

1.png

getRequestUri(request) 方法获取URI 的值,并调用 decodeAndCleanUriString() 处理。

2.png

decodeAndCleanUriString()中对 ; 进行了截取。
此时contextPath值为/samples_web_warrequestUri值为/samples_web_war/login.jsp
然后判断requestUri是否以contextPath开始,是的话将其替换为/
其实这里面可以吧requestUri理解为路由

处理之后的请求 URL 将会使用 AntPathMatcher#doMatch 进行权限验证。
此时发现,Shiro中对URI并没有进行路径的标准化处理,这样当URI中存在特殊字符时,就存在绕过风险

漏洞复现

1
2
3
4
5
6
[urls]
/login.jsp = authc
/logout = logout
/account/** = authc
/remoting.jsp = authc, perms["audit:list"]
/** = anon

image-20240209011817441

Apache Shiro ‘login.jsp’安全绕过漏洞 CVE-2014-0074

漏洞信息

漏洞编号: CVE-2014-0074 / CNVD-2014-03861 / SHIRO-460
影响版本:shiro 1.x < 1.2.3
漏洞描述 :当程序使用LDAP服务器并启用非身份验证绑定时,远程攻击者可借助空的用户名或密码利用该漏洞绕过身份验证。
漏洞补丁:Commit

漏洞分析

当使用了未经身份验证绑定的 LDAP 服务器时,允许远程攻击者通过空用户名或空密码绕过身份验证。

Shiro < 1.3.2 验证绕过漏洞 CVE-2016-6802

漏洞信息

漏洞编号:CVE-2016-6802 / CNVD-2016-07814
影响版本:shiro < 1.3.2
漏洞描述:Shiro未对ContextPath做路径标准化导致权限绕过
漏洞补丁: Commit
参考 : su18师傅

漏洞详解

本漏洞类似 CVE-2010-3863,依旧是路径标准化导致的问题,不过之前是在 RequestURI 上,本漏洞是在 ContextPath 上。
之前提到,Shiro 调用 WebUtils.getPathWithinApplication() 方法获取请求路径。逻辑如下:

1
2
3
4
5
6
7
8
9
10
public String getPathWithinApplication(HttpServletRequest request) {
String contextPath = this.getContextPath(request);
String requestUri = this.getRequestUri(request);
String path = this.getRemainingPath(requestUri, contextPath, true);
if (path != null) {
return StringUtils.hasText(path) ? path : "/";
} else {
return requestUri;
}
}

其中调用 getContextPath() 方法,获取 contextPath ;调用 getRequestUri() 方法,获取 uri

getContextPath() 方法调用 decodeRequestString 进行 URLDecode
6802_2.png
由于获取的 ContextPath 没有标准化处理,如果出现一些特殊字符使ContextPath与实际不符,都会导致在 StringUtils.startsWithIgnoreCase() 方法判断时失效,直接返回完整的RequestURI

复现

登录账户lonestarr,该账户对页面remoting.jsp没有访问权限,在跟路径前加任意路径,再加../即可实现绕过
6802_3.png

6802_4.png

这么一看哈,其实,感觉,也没那么难?
我要成为厉害的人!

Shiro < 1.5.2 验证绕过漏洞 CVE-2020-1957

漏洞信息

漏洞编号:CVE-2020-1957 / CNVD-2020-20984 /SHIRO-682
影响版本:shiro < 1.5.2
漏洞描述:利用 ShiroSpringURL 的处理的差异化,越权并成功访问。
漏洞补丁:Commit Commit [Commit](

漏洞分析

SHIRO-682

本漏洞起源于 SHIRO-682。在 Spring 中,/resource/xx/resource/xx/ 都会被截成/resource/xx以访问相应资源;在 shiro 中,/resource/xx/resource/xx/被视为两个不同路径。所以在 Spring 集成 shiro 时,只需要在访问路径后添加 / 就存在绕过权限校验的可能。
下面通过复现进行分析(分析、测试版本1.4.2):
首先shiro.ini中[urls]配置如下:

1
2
3
4
5
6
7
[urls]
# anon:匿名拦截器,不需登录就能访问,一般用于静态资源,或者移动端接口。
# authc:登录拦截器,需要登录认证才能访问的资源。
/login.jsp = authc
/logout = logout
/toJsonPOJO = authc, perms["audit:list"]
/** = anon

输入/toJsonPOJO时,shiro对其进行判断,从shiro.ini或其他配置中进行匹配。当匹配到/toJsonPOJO时,匹配成功,跳出循环。
1957_1.png
此时,跳转至登陆界面。
输入/toJsonPOJO/时,shiro对其进行判断,当匹配到/toJsonPOJO时,匹配失败,继续匹配;当匹配到/**时,匹配成功,跳出循环。
1957_2.png
接着到了springframework中的判断,这里/toJsonPOJO/toJsonPOJO是可以匹配成功的
1957_3.png
此时,成功绕过
1957_4.png

其他绕过方式

除了上面的绕过方式,本 CVE 还存在另一个绕过。利用的是 shirospringurl 中的 ; 处理的差异进行绕过并成功访问。
分析、测试版本1.4.2

绕过分析

首先进入Shiro
首先在org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver.class#getChain处下断点,进行调试,访问http://localhost:8080/xx/..;/toJsonPOJO
1957_6.png

单步调试进入this.getPathWithinApplication(request),在WebUtils#getPathWithinApplication()中,通过getContextPath(request),获取到上下文信息后,再用getRequestUri(request)获取具体的uri。进入getRequestUri()方法,在return前,获取到的uri/xx/..;/toJsonPOJO
1957_5.png
接下来分析一下return normalize(decodeAndCleanUriString(request, uri));
首先进入decodeAndCleanUriString
传入的参数uri/xx/..;/toJsonPOJO,然后通过语句int semicolonIndex = uri.indexOf(59);找出uri中分号的位置,59也就是;ASCII码
如果uri中有分号,就返回分号前的字段,否则返回整个uri
1957_7.png
接着进入normalize,参数uri已经变成/xx/..normalize内部对传入的路径进行标准化规范处理,相关操作包括替换反斜线、替换///等,最后得到返回的uri
此时return normalize(decodeAndCleanUriString(request, uri));结果为/xx/..,也就是说getRequestUri(request)获取的uri/xx/..
1957_8.png

1957_9.png

一路回到getChain,经过上面的步骤,得到requestURI值为/xx/..,接下来在while循环里使用pathMatches(pathPattern, requestURI)进行权限校验,此时只有/**能够与/xx/..匹配成功,/**anon权限,不需要登陆就能访问,绕过了/toJsonPOJOauthc权限
1957_10.png

此时Shiro部分的权限绕过了,那么Spring部分的路径是怎么匹配的呢?
url经过shiro的处理认证通过后,就会进入spring中进行解析,我们在UrlPathHelper#getLookupPathForRequest下断点
1957_11.png
先进入getPathWithinApplication(),通过this.getRequestUri(request)获取uri
1957_12.png
获取到的uri值为/xx/..;/toJsonPOJO,在return之前进入decodeAndCleanUriString(request, uri)
1957_14.png
传进来的参数uri/xx/..;/toJsonPOJO,经过removeSemicolonContent(uri)后移除uri//之间的的分号以及分号后面的内容;经过decodeRequestString(request, uri)后对uri进行解码;经过getSanitizedPath(uri)后将路径中//替换为/。此时返回的uri值为/xx/../toJsonPOJO
1957_15.png

1957_16.png
步入getPathWithinServletMapping()后,传入的参数pathWithinApp值为/xx/../toJsonPOJO。依次通过UrlPathHelper#getServletPathHttpServletRequestWrapper#getServletPathRequest#getServletPath获取到我们实际访问的url:http://localhost:8080/toJsonPOJO后返回,最终实现绕过权限访问
1957_13.png

1957_17.png

经过测试当uri123;/..;345/;../.;/alter/..;/;/;///////;/;/;awdwadwa/toJsonPOJO时,Shiro/123进行权限验证;
1957_18.png
Springorg.springframework.web.util.UrlPathHelper中,getPathWithinApplication(request)值为/123/.././alter/../toJsonPOJO;
1957_19.png

1957_20.png
this.getPathWithinServletMapping(request, pathWithinApp)值为/toJsonPOJO,可以进行绕过
1957_21.png

上面这个 payload 只能在较低版本的 Spring Boot 上使用。
根据Ruil1n 师傅介绍:
Spring Boot 版本在小于等于 2.3.0.RELEASE 的情况下,alwaysUseFullPath 为默认值 false,这会使得其获取 ServletPath ,所以在路由匹配时相当于会进行路径标准化包括对 %2e 解码以及处理跨目录,这可能导致身份验证绕过。而反过来由于高版本将 alwaysUseFullPath 自动配置成了 true 从而开启全路径,又可能导致一些安全问题。
所以在高版本上只能试着寻找逻辑上有没有漏洞,然后进行绕过。比如程序配置了访问路径 /alter/**anon,但是指定了其中的一个 /alter/pageauthc。这时在不跳目录的情况下,可以使用如下请求绕过:
http://127.0.0.1:8080/alter//;aaaa/;...///////;/;/;awdwadwa/page

我这里末尾加了/才成功。不过也无所谓了

Apache Shiro < 1.5.3 权限绕过漏洞 CVE-2020-11989

漏洞信息

漏洞编号:CVE-2020-11989 / SHIRO-782
影响版本:shiro < 1.5.3
漏洞描述:在Shiro < 1.5.3的情况下,将ShiroSpring Controller一起使用时,相应请求可能会导致身份验证绕过。
漏洞补丁:Commit
参考: 腾讯安全玄武实验室 Ruilin师傅 边界无限 淚笑师傅

这个漏洞有两种绕过方式,分别由腾讯安全玄武实验室的Ruilin师傅和来自边界无限的淚笑师傅报告

shiro文件方面科普

Shiro主要的三个文件:
ShiroConfig,LoginController,Myrealm

权限配置:ShiroConfig
其中/doLogin无需权限验证即可访问,用于登录界面
而test/文件下目录需要登陆权限认证后才可以进行访问

image-20240212143229567

登陆控制:LoginController
其中设置了访问目录返回的内容

image-20240212143248394

Myrealm:其中储存着用户类信息像我们登陆所用的密码。
image-20240212143303608

漏洞分析 —— 两次解码绕过

限制

这个场景下需要一些限制条件,首先配置文件的ant风格需要是*而不是**,测试发现,?也可以
另外controller需要接收的request参数(@PathVariable)的类型需要是String,否则将会出错。
11989_3.png

复现

首先复现一下,测试版本 1.5.2

编写Controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@RequestMapping("/toJsonList/{name}")
@ResponseBody
public List<User> toJsonList(@PathVariable String name){
System.out.println("返回json集合数据");
User user1 = new User();
user1.setName("alter1");
user1.setAge(15);

User user2 = new User();
user2.setName("alter2");
user2.setAge(12);

List<User> userList = new ArrayList<User>();
userList.add(user1);
userList.add(user2);

return userList;
}

配置对应的shiro.ini

1
2
[urls]
/toJsonList/* = authc

此时请求/toJsonList/aaa那么将会被禁止。
11989_1.png
但是这里我们可以通过url双编码的方式来绕过。

1
/ -> %2f ->%25%32%66

11989_2.png
测试发现下面四种组合只有前两组可以绕过

1
2
3
4
5
6
7
yes
/toJsonList/a%25%32%66a
/toJsonList/%25%32%66

no
/toJsonList/%25%32%66a
/toJsonList/a%25%32%66

分析

首先要清楚Shiro支持 Ant 风格的路径表达式配置。ANT 通配符有 3 种,如下所示:

通配符 说明
? 匹配任何单字符
* 匹配0或者任意数量的字符
** 匹配0或者更多的目录

解释一下就是/** 之类的配置,匹配路径下的全部访问请求,包括子目录及后面的请求,如:/admin/** 可以匹配 /admin/a 或者 /admin/b/c/d 等请求。
对于/*的话 ,单个 * 不能跨目录,只能在两个 / 之间匹配任意数量的字符,如 /admin/* 可以匹配 /admin/a 但是不能匹配 /admin/b/c/d
那么问题来了,如果我们将其配置为/toJsonList/*,但是我们访问形如/toJsonList/a/b这种路径,此时就会绕过访问权限。

我们还记得为了修复CVE-2020-1957,shiro在1.5.2版本进行了更新,将request.getRequestURI() 修改为 request.getContextPath()request.getServletPath()request.getPathInfo() 拼接构造uri。根据网上师傅们的总结,这几个方法的差异性如下:

  • request.getRequestURL():返回全路径;
  • request.getRequestURI():返回除去Host部分的路径;
  • request.getContextPath():返回工程名部分,如果工程映射为/,则返回为空;
  • request.getServletPath():返回除去Host和工程名部分的路径;
  • request.getPathInfo():仅返回传递到Servlet的路径,如果没有传递额外的路径信息,则此返回Null

第一次解码发生在request.getServletPath()
11989_4.png
第二次解码发生在decodeAndCleanUriString() -> decodeAndCleanUriString() -> decodeRequestString() -> URLDecoder.decode()
11989_5.png
因此org.apache.shiro.web.util.WebUtils#getRequestUri进行了两次解码,将/toJsonList/a%25%32%66a解码成/toJsonList/a/a
接着就走到org.apache.shiro.util.AntPathMatcher#doMatch进行权限验证,/toJsonList/a/a不满足配置中的toJsonList/*,因此成功绕过。

但还要看Spring是怎么对其进行解析的
org.springframework.web.uti.UrlPathHelper#getPathWithinApplication中,将url解析为/toJsonList/a%2fa,这样其实就表示/toJsonList/{name}中的name值为a%2fa
11989_6.png

分析完之后, 也就解释了为什么下面四种组合只有前两组可以绕过
(这种二次解码的方式我测试只适用于1.5.2的版本,之前的版本使用a%25%32%66a测试,因为只有一次解码,会跳转至登陆界面;a%2fa测试直接返回400 Bad Request

漏洞分析 —— 根路径差异化解析绕过

限制

  1. Shiro >= 1.5.2 的话,应用不能部署在根目录,如果为根目录则 context-path 为空, CVE-2020-1957 更新补丁将 URL 格式化。
  2. Spring 控制器中没有另外的权限校验代码

复现

本次复现使用的是1.4.2版本的shiro所以应用根目录是什么都没有关系

配置为

1
2
/alter/* = authc
/** = anon

新增一个controller

1
2
3
4
5
6
7
8
9
10
@RequestMapping("/alter/test")
@ResponseBody
public List<User> test(){
User user1 = new User();
user1.setName("alter");
user1.setAge(15);
List<User> userList = new ArrayList<User>();
userList.add(user1);
return userList;
}

输入地址http://localhost:8080/;/shirodemo/alter/testorg.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver#getChain会进行如下操作获取uri
11989_7.png
此时uri结果为/,绕过配置/alter/* = authc,符合配置/** = anon,达到绕过目的。
Spring在处理uri时直接进行路径标准化,去掉了分号

11989_13.png

11989_8.png
Shiro < 1.5.2版本的话,根路径是什么没有关系
11989_9.png

漏洞修复

ShiroCommit 中修改了 URL 获取的逻辑,不单独处理 context-path,这样不会导致绕过,同时也避免了二次 URL 解码的问题。
回退了 WebUtils#getRequestUri 的代码,并将其标记为 @Deprecated
11989_10.png
可以看到,shiro建议使用 getPathWithinApplication() 方法获取路径减去上下文路径,或直接调用 HttpServletRequest.getRequestURI() 方法获取。

WebUtils#getPathWithinApplication 方法,修改了使用 RequestUri 去除 ContextPath 的方式,改为使用 getServletPath(request) + getPathInfo(request))。然后使用 removeSemicolon 方法处理分号问题,normalize 方法进行路径标准化。
11989_11.png

11989_12.png

Shiro < 1.6.0 验证绕过漏洞 CVE-2020-13933

漏洞信息

漏洞编号:CVE-2020-13933 / CNVD-2020-46579
影响版本:shiro < 1.6.0
漏洞描述:Shiro 由于处理身份验证请求时存在权限绕过漏洞,特制的HTTP请求可以绕过身份验证过程并获得对应用程序的未授权访问。
漏洞补丁:Commit

漏洞分析

这个CVE其实就是对CVE-2020-11989 patch的绕过。上一个CVE使用 getServletPath(request) + getPathInfo(request)) 获取uri,回顾一下:

  • request.getServletPath():返回除去Host和工程名部分的路径;
  • request.getPathInfo():仅返回传递到Servlet的路径,如果没有传递额外的路径信息,则此返回Null

ShirogetChain内进行权限验证,首先通过getPathWithinApplication(request)获得uri。从下图可以看到,更新后使用HttpServletRequest.getRequestURI() 方法获取uri;然后使用removeSemicolon去除uri中的分号,这里去除的是分号及分号后面的内容;然后使用normalize进行路径标准化。
13933_1.png
此时得到的路径为/hello,绕过了配置中的权限。
接着看Spring是怎么处理路径的:
org.springframework.web.util#UrlPathHelper中的getPathWithinApplication方法内,使用getRequestUri(request)方法获取uri
13933_2.png
Shiro处理的差异达到既绕过Shiro权限验证又成功访问的目的。
13933_3.png

漏洞修复

shiro1.6.0版本中,org.apache.shiro.spring.web#ShiroFilterFactoryBean中增加了/**的默认路径配置,使其可以全局匹配进行过滤校验
13933_4.png
默认的/**配置对应一个全局的 filterInvalidRequestFilter,这个类继承了 AccessControlFilter。用来过滤特殊字符(分号、反斜线、非ASCII码字符),并返回 400 状态码。
13933_5.png

Apache Shiro < 1.7.0 权限绕过漏洞 CVE-2020-17510

漏洞信息

漏洞编号:CVE-2020-17510 / CNVD-2020-60318
影响版本:shiro < 1.7.0
漏洞描述:第三种AntPathMatcher的绕过方式
漏洞补丁:Commit

漏洞分析

这个漏洞还是对 AntPathMatcher 的继续绕过,在CVE-2020-11989CVE-2020-13933分别尝试了 / 的双重 URL 编码和 ;URL 编码绕过,归根到底这种方式还是因为ShiroSpringURI处理的差异化导致的。那么字符 . 是不是也可以进行绕过呢?其实是可以的(测试环境Shiro 1.6.0SpringBoot 2.5.3
还是添加如下配置和Controller

1
2
3
4
5
map.put("/hello/*", "authc");
@GetMapping("/hello/{name}")
public String hello(@PathVariable String name) {
return "hello";
}

Shiro获得的uri/hello时,是无法和/hello/*匹配的,所以就在/hello后面加上%2e,这样Shiro解码之后变成/hello/.,然后路径标准化成为/hello,绕过身份验证
17510_1.png
对于Spring来说,正如之前讲的,Spring Boot 版本在小于等于 2.3.0.RELEASE时,会对uri进行解码然后路径标准化,这样得到的路径为/hello,没有页面与之匹配。所以只有当 Spring Boot 版本在大于 2.3.0.RELEASE时标准化路径后/hello/%2e,然后解码/hello/.
17510_2.png
17510_3.png
下面的payload都可以使用:

1
2
3
4
/%2e
/%2e/
/%2e%2e
/%2e%2e/

漏洞修复

Commit中发现org.apache.shiro.spring.web下新增了ShiroUrlPathHelper类,属于UrlPathHelper的子类,重写了getPathWithinApplicationgetPathWithinServletMapping两个方法
17510_4.png

其实我认为1.7.1才算真正的更新,因为它是依次对原uri和去除uri尾部斜线的uri进行验证,这样就可以避免因直接去除尾部uri导致/hello/hello/*不匹配而导致的绕过问题。

补丁问题

问题一

根据官方发布的公告,发现其实需要配置shiro-spring-boot-web-starter才有效

1
2
3
4
5
6
 if you are NOT using Shiro’s Spring Boot Starter
(`shiro-spring-boot-web-starter`), you must configure add the
ShiroRequestMappingConfig auto configuration[1] to your application or
configure the equivalent manually[2].
[1] https://shiro.apache.org/spring-framework.html#SpringFramework-WebConfig
[2]https://github.com/apache/shiro/blob/shiro-root-1.7.0/support/spring/src/main/java/org/apache/shiro/spring/web/config/ShiroRequestMappingConfig.java#L28-L30

由于我导入的dependency如下

1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.6.0</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.6.0</version>
</dependency>

如果直接将版本升为1.7.0的话,其实并没有触发更新,原payload还是可以绕过。
只有按照上面官网所述的两种配置方式修改后,才能防御成功

问题二

在旧版的SpringBoot 中,当我们需要获取当前请求地址的时候,直接通过如下方式获取:

1
2
//org.springframework.web.servlet.handler#getHandlerInternal
String lookupPath = this.getUrlPathHelper().getLookupPathForRequest(request);

但是在新版Spring里边,通过如下方式获取

1
String lookupPath = this.initLookupPath(request);

initLookupPath()代码如下:

1
2
3
4
5
6
7
8
9
10
protected String initLookupPath(HttpServletRequest request) {
if (this.usesPathPatterns()) {
request.removeAttribute(UrlPathHelper.PATH_ATTRIBUTE);
RequestPath requestPath = ServletRequestPathUtils.getParsedRequestPath(request);
String lookupPath = requestPath.pathWithinApplication().value();
return UrlPathHelper.defaultInstance.removeSemicolonContent(lookupPath);
} else {
return this.getUrlPathHelper().resolveAndCacheLookupPath(request);
}
}

如果this.usesPathPatterns() == true的话,就可以绕开问题一中我们配置的ShiroUrlPathHelper
17510_5.png
此时也成功绕过。
17510_6.png

所以这就存在一个矛盾:只有Spring Boot 版本在大于 2.3.0.RELEASE才能触发这个漏洞,修复之后由于版本问题,SpringBoot又不走那条语句。
另外在配置的时候,当Spring Boot 版本在小于等于 2.3.0.RELEASE,如2.1.5.RELEASE,时,this.getUrlPathHelper()并不是ShiroUrlPathHelper,不清楚是不是配置问题还是版本兼容问题。
17510_7.png

Apache Shiro < 1.7.1 权限绕过漏洞CVE-2020-17523

漏洞信息

漏洞编号:CVE-2020-17523 / CNVD-2021-09492
影响版本:shiro < 1.7.1
漏洞描述:Shiro 1.7.1 之前的版本,在将 ShiroSpring 结合使用时,特制的 HTTP 请求可能会导致身份验证绕过。
漏洞补丁:Commit

漏洞分析

CVE-2020-17510那样,这个漏洞可以使用空格%20进行绕过。
我们输入路径为http://localhost:8080/hello/%20,进入getChain,经过路径获取后要进行权限的匹配与验证
17523_1.png
这里主要看一下/hello//hello/*比较时发生了什么
经过pathMatches(pathPattern, requestURI) -> pathMatcher.matches(pattern, path) -> match(pattern, source) -> doMatch(pattern, path, true) 来到了主要的判断方法doMatch()
其中StringUtils.tokenizeToStringArray()方法是将它的参数,也就是传进来的两个路径拆解成字符串数组,然后进行比较。
进入方法,可以看到当对空格进行转换时,直接trim为空
17523_2.png

17523_3.png
这样就导致与shiro中的配置本意想违背,导致绕过。
17523_4.png
然后在Spring中的处理时,uri又包含空格,这样就能访问到/hello/%20页面
17523_5.png

漏洞修复

Commit中,主要修复点AntPathMatcher.java,在tokenizeToStringArray方法中加了falsetrue两个参数
17523_6.png
可以看到,当第三个参数为false时,即trimTokensfalse,此时就不会对token进行trim
17523_7.png

Apache shiro 认证机制不恰当 CVE-2021-41303

漏洞信息

漏洞编号:CVE-2021-41303 / SHIRO-825
影响版本:shiro < 1.8.0
漏洞描述:1.8.0 之前的 Apache Shiro,在 Spring Boot 中使用 Apache Shiro 时,特制的 HTTP 请求可能会导致身份验证绕过。用户应该更新到 Apache Shiro 1.8.0
漏洞补丁:Commit
参考:[threedr3am师傅](https://threedr3am.github.io/2021/09/22/从源码diff分析Apache-Shiro 1.7.1版本的auth bypass(CVE-2021-41303)/)

漏洞分析

根据[threedr3am师傅](https://threedr3am.github.io/2021/09/22/从源码diff分析Apache-Shiro 1.7.1版本的auth bypass(CVE-2021-41303)/)博客提供的方向,看了一下Shiro 1.7.1前后PathMatchingFilterChainResolver#getChain的对比
41303_1.png

41303_2.png
发现在1.7.1版本中,先是对pathPattern和requestURI进行比较,比较成功,返回:

1
filterChainManager.proxy(originalChain, pathPattern);

否则对删除尾部斜线的pathPattern和requestURI进行比较,比较成功,跳出循环,返回:

1
filterChainManager.proxy(originalChain, requestURINoTrailingSlash);

但是正常访问,都会返回第一个proxy,什么时候才能绕过第一个比较并符合第二个比较呢?
可以看到,两者差别是对uri尾部斜线的处理,所以当在uri尾部加一个/,就会进入第二种比较方式。
41303_3.png
结合之前的多次调试再根据threedr3am师傅博客中的认证,可以知道shiro的认证鉴权会根据配置的先后顺序去依次实施
所以当我有如下配置时:

1
2
map.put("/admin/*", "authc");
map.put("/admin/page", "anon");

循环中先匹配到/admin/*(这里是通过while语句对去除尾部斜线的uri进行匹配),然后跳出循环,进入到filterChainManager.proxy(originalChain, requestURINoTrailingSlash);,注意,这里真正的参数就是去除尾部斜线的uri,也就是/admin/page,所以在DefaultFilterChainManager#getChain中得到的权限是anon,这样就达到绕过目的。
41303_4.png

41303_5.png

漏洞修复

直接将filterChainManager.proxy的第二个参数改为pathPattern,直接传配置中的uri
41303_6.png

Apache Shiro RegExPatternMatcher 权限绕过漏洞 CVE-2022-32532

漏洞信息

漏洞编号:CVE-2022-32532
影响版本:shiro < 1.9.1
漏洞描述:在1.9.1之前的Apache Shiro中,RegexRequestMatcher可能会被错误配置,从而在某些servlet容器上被绕过。应用程序使用RegExPatternMatcher.的正则表达式可能容易被授权绕过。
漏洞补丁:Commit
参考:4ra1n师傅

###漏洞分析

这是最新的一个洞,看Shiro发布的公告显示,是由于RegexRequestMatcher的错误配置导致的问题。
简单了解了一下,RegexRequestMatcherAntPathMatcher类似,都是Shiro用于路径匹配的配置,只是RegexRequestMatcher需要用户自己配置。
根据4ra1n师傅的分析,可以知道,正常正则表达式.并不包含\r\n字符
32532_1.png
修改成如下代码就可修复问题

1
2
// flag为Pattern.DOTALL时,表达式 .可以匹配任何字符,包括行结束符。
Pattern pattern = Pattern.compile(regex,Pattern.DOTALL);

32532_2.png
那么回头看一下RegexRequestMatcher用于匹配的代码

1
2
3
4
5
6
7
8
9
public boolean matches(String pattern, String source) {
if (pattern == null) {
throw new IllegalArgumentException("pattern argument cannot be null.");
} else {
Pattern p = Pattern.compile(pattern);
Matcher m = p.matcher(source);
return m.matches();
}
}

可以发现,当pattern存在带.的正则表达式并且source中存在\r\n字时,此时判断错误。
此时我们在配置完RegexRequestMatcher之后增加如下Controller

1
2
3
4
5
@RequestMapping(path = "/alter/{value}")
public String alter(@PathVariable String value) {
System.out.println("绕过成功");
return "绕过成功"+value;
}

增加如下配置

1
2
//myFilter.java中设置成需要权限
manager.addToChain("/alter/.*", "myFilter");

这样正常访问/alter/aaa是被拒绝的,但是当访问/alter/a%0aaa/alter/a%0daa时就会绕成验证,访问成功
32532_3.png

32532_4.png

32532_6.png
这个洞限制还是比较多的,既要服务器配置了RegExPatternMatcher,又要设置带有.的正则表达式

漏洞修复

Commit可以看到,对compile方法设置了flag
32532_5.png