Foreword
自struts2官方纰漏S2-066毛病已经有一段时间,期间断断续续地写,直到最近才完成。羞愧地回顾一下官方通告:
2023.12.9发布,编号CVE-2023-50164,重要影响版本是 2.5.0-2.5.32 以及 6.0.0-6.3.0,描述中提到了文件上传毛病和目次穿越毛病。开始以为这是个组合毛病,实在不是,这是一个毛病,看了几篇大佬的文章,有的把它称为“文件上传目次穿越毛病”,也有道理。
Prepare
准备工作就是搭建项目,用Tomcat跑,调试好断点,回顾下struts2的布局。篇幅有限,这里只贴一张struts2自身的配置文件:
[img=720,430.39285714285717]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202403191435485.png[/img]
struts2有浩繁的Filter和Intercepter,它的配置逻辑是,除文件中定义的class、package以外,别的全部拦截。对于S2-066,处理一个哀求要颠末的几个关键类包括Dispatcher、Interceptor、HttpParameters以及UploadAction。使用下面的poc:
[img=720,322.39285714285717]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202403191435374.png[/img]
Dispatcher
哀求起首会进入著名的Dispatcher。multi参数对应的就是body数据,包含upload、fileName、contentType三个变量,无误:
[img=720,430.39285714285717]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202403191435918.png[/img]
request中另有一个参数,uploadFileName=../../z127.txt,这个是污染参数,文件上传的目的地,也是利用这个毛病的目标。
[img=720,430.39285714285717]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202403191436450.png[/img]
走到这里Dispatcher只是简单处理一下哀求然后交给Interceptor,无非常。
【----帮助网安学习,以下所有学习资料免费领!加vx:dctintin,备注 “博客园” 获取!】
① 网安学习成长路径思维导图
② 60+网安经典常用工具包
③ 100+SRC毛病分析陈诉
④ 150+网安攻防实战技术电子书
⑤ 最权威CISSP 认证考试指南+题库
⑥ 超1800页CTF实战技巧手册
⑦ 最新网安大厂面试题合集(含答案)
⑧ APP客户端安全检测指南(安卓+IOS)
FileUploadInterceptor
拦截器先是把request包装了一下,范例是MultiPartRequestWrapper。
[img=720,430.39285714285717]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202403191437676.png[/img]
这里与Dispatcher一样,哀求参数还是multi和request两部门,也无非常。
[img=720,430.39285714285717]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202403191437242.png[/img]
而且遍历只有一次 ,由于真正的body只有一个,就是那个multi。
[img=720,430.39285714285717]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202403191437906.png[/img]
在遍历过程中struts2还出现了硬编码现象,要求文件名参数必须以FileName结尾,且拼接完成的文件名前缀就是body中的{upload}名称,这就给exp带来了肯定限定:
[img=720,430.39285714285717]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202403191437440.png[/img]
此外,留意这里的279行:- // get the name of the file from the input tag
- String[] fileName = multiWrapper.getFileNames(inputName);
复制代码 使用的是MultiPartRequest接口的方法,而这个接口在S2-066中是由JakartaMultiPartRequest实现。使用下面这个poc进行目次穿越并断点检测一下:
[img=720,286.39285714285717]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202403191438500.png[/img]
发现目次穿越失败,文件没有放在指定目次下。分析源码:
[img=720,430.39285714285717]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202403191438366.png[/img]
参数覆盖原本想用../../z126.txt,方法的输入参数确实也是如许接收的,但在这个方法中struts2会对文件名进行截断,终极输出的文件名会变为 z126.txt,文件也就不会出现目次穿越的现象。因此目次穿越不是发生在这里,让struts2自己背这个锅多少有点冤。body中的数据组装完毕是下面如许,size等于3,仍然无误:
[img=720,430.39285714285717]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202403191438180.png[/img]
HttpParameters
来到HttpParameters查看接收的参数,还是upload、contentType、fileName三个:
[img=720,430.39285714285717]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202403191439708.png[/img]
但是参数接收完后就不正常了,除了原本的UploadFileName(留意首字母是大写),还多了一个uploadFileName(留意首字母是小写),size也变成了4。这就是Struts2官方所表明的大小写敏感,即对大写的Upload和小写的upload分别做处理。从这里开始,S2-066才露出真正面目:
[img=720,430.39285714285717]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202403191439093.png[/img]
HttpParameters实现了Map接口,所以本质上它还是一个map,这也是组装参数最常用的方式。但不管是HashMap还是TreeMap,自己不会出现覆盖的题目。用一个小实验证明:
[img=720,430.39285714285717]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202403191439883.png[/img]
走到这里,HttpParameters对参数的处理开始出现非常,但依然没有发生覆盖。
UploadAction
终于到Action了。引用一段struts2官方的描述:
An attacker can manipulate file upload params to enable paths traversal and under some circumstances this can lead to uploading a malicious file which can be used to perform Remote Code Execution.
通过操控上传参数,黑客能够出发目次穿越毛病,如许一来,在某些情况下可以上传恶意文件,从而进行RCE。换种说法,S2-066是框架自身、软件工程师、Java反射机制共同作用的效果。走到这里,为了简化代码,UploadAction即是Action又是Entity。而在Entity的实例化过程中,必然是通过setXX属性来赋值。所以就有了setUploadFileName(留意首字母大写)和setuploadFileName(留意首字母小写)的需求 。而在Entity的setter与getter中,这两种需求都会被当做一种,即setUploadFileName,因此覆盖也就发生了。正常情况下实例化方法只走一遍,如contentType:
[img=720,430.39285714285717]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202403191439355.png[/img]
而setUploadFileName第一遍是z106.txt:
[img=720,430.39285714285717]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202403191439133.png[/img]
第二遍是../../z127.txt:
[img=720,430.39285714285717]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202403191439343.png[/img]
实例化完成后,uploadFileName属性已被覆盖:
[img=720,430.39285714285717]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202403191440792.png[/img]
查看物理路径,上传乐成:
[img=720,293.6842105263158]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202403191440057.png[/img]
POCs
参数不是filename结尾,失败:
[img=720,298.60714285714283]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202403191440202.png[/img]
参数不符合FileName大小写要求,失败:
[img=720,293.7857142857143]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202403191440252.png[/img]
大写覆盖小写失败:
大写覆盖大写失败:
[img=720,321.10714285714283]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202403191440445.png[/img]
小写覆盖小写失败:
[img=720,321.75]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202403191441141.png[/img]
小写覆盖大写乐成,文章开头所用。另外覆盖也可以放在body中:
[img=720,290.25]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202403191441775.png[/img]
验证:
[img=720,189.26470588235293]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202403191441975.png[/img]
利用条件多少有点苛刻,但杀伤力不输struts2过去那一堆,CVSS3.0评分9.8,CRITICAL。
[img=720,441.1612106238419]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202403191434256.bmp[/img]
更多网安技能的在线实操练习,请点击这里>>
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |