Pocsuite3源码实现浅析 插件调用流程

2019-7-24 小屿 Python

瞎看一通后发现了一篇文章:https://paper.seebug.org/913/

Pocsuite3 是由知道创宇404实验室打造的一款开源的远程漏洞测试框架,我之前并没有怎么使用过,这几天学习了一下它的源码,当然我非常菜,只是简单记录一下自己而已。


Pocsuite3核心功能就是加载插件并执行验证漏洞,当然它提供了丰富的执行模式,例如调用zoomeye,shodan、生成shellcode、调用api验证dns和http请求等,以及拥有一个强大的漏洞库和贡献poc的社区。


程序入口在pocsuite3/cli.py,也可以通过console.py实现命令行交互模式。


程序执行比较繁杂,我简化了执行逻辑如下。简化后的程序逻辑十分直观。

from pocsuite3.lib.core.register import load_file_to_module

from pocsuite3.lib.core.datatype import AttribDict

from pocsuite3.lib.core.data import kb, conf

kb.registered_pocs = AttribDict()
conf.ipv6 = False
load_file_to_module("pocs/thinkphp_rce2.py")
poc_module = kb.registered_pocs["pocs_thinkphp_rce2"]

result = poc_module.execute("http://127.0.0.1")
output = AttribDict(result.to_dict())
print(output)

首先Pocsuite3模仿了sqlmap实现了AttribDict来存储和返回数据,加载的插件会存储在kb.registered_pocs里面。

加载插件的方法位于pocsuite3/lib/core/register.py的load_file_to_module方法

加在插件通过importlib类实现,示例如下。

import importlib.util
def import_source(module_name):
    module_file_path = module_name.__file__
    module_name = module_name.__name__
    module_spec = importlib.util.spec_from_file_location(module_name, module_file_path)
    module = importlib.util.module_from_spec(module_spec)
    module_spec.loader.exec_module(module)
    print(dir(module))
    msg = 'The {module_name} module has the following methods: {methods}'
    print(msg.format(module_name=module_name, methods=dir(module)))
if __name__ == '__main__':
    import os
    import_source(os)

加载插件后会执行末尾的register_poc方法,该方法将插件poc类实例化传入kb.registered_pocs里。

然后执行位于pocsuite3/lib/core/poc.py的插件父类POCBase的execute方法,execute调用_execute方法,通过传入参数判断执行payload的方式,验证漏洞或者是获取shell等。

    def _execute(self):
        if self.mode == 'shell':
            if not hasattr(self, "_shell"):
                raise NotImplementedError
            output = self._shell()
        elif self.mode == 'attack':
            output = self._attack()
        else:
            output = self._verify()

        return output

    def execute(self, target, headers=None, params=None, mode='verify', verbose=True):
        self.target = target
        self.url = parse_target_url(target) if self.current_protocol == POC_CATEGORY.PROTOCOL.HTTP else self.build_url()
        self.headers = headers
        self.params = str_to_dict(params) if params else {}
        self.mode = mode
        self.verbose = verbose
        self.expt = (0, 'None')
        # TODO
        output = None

        try:
            output = self._execute()

        except NotImplementedError as e:
            self.expt = (ERROR_TYPE_ID.NOTIMPLEMENTEDERROR, e)
            logger.log(CUSTOM_LOGGING.ERROR, 'POC: {0} not defined "{1}" mode'.format(self.name, self.mode))
            output = Output(self)

然后返回的原始结果如下。

AttribDict([('error_msg', (0, 'None')), ('result', {'VerifyInfo': {'URL': '/index.php?s=captcha', 'Postdata': '_method=__construct&filter[]=phpinfo&method=get&server[REQUEST_METHOD]=1'}}), ('status', 1), ('url', 'http://127.0.0.1'), ('mode', 'verify'), ('vul_id', '97767'), ('name', 'Thinkphp 5.0.x 远程代码执行漏洞'), ('app_name', 'thinkphp'), ('app_version', 'thinkphp5.0.23')])


接着看插件的编写,插件继承自POCBase类,开头定义poc各种信息,id、作者、时间、版本等。

_verify方法为实现漏洞验证的方法,_attack即为攻击,_shell即为反弹shell之类的操作


插件内register_poc方法为加载插件时候进行实例化类并传入定义的AttribDict的操作。

def register_poc(poc_class):
    module = poc_class.__module__.split('.')[0]
    if module in kb.registered_pocs:
        kb.current_poc = kb.registered_pocs[module]
        return
    kb.registered_pocs[module] = poc_class()
    kb.current_poc = kb.registered_pocs[module]


值得注意的是pocsuite3对一些引用包进行了简单修改,例如在pocsuite3/lib/request对requests删除了ssl验证和警告消息以及重写了一些方法实现Network request options功能,具体我也没仔细看。


最后简化代码,简单修改删除了AttribDict和插件内的register_poc方法等,自己基于Pocsuite3的逻辑代码实现了简单的插件调用执行验证漏洞返回python字典结果,当然这样做并没有什么意义。

标签: Pocsuite

发表评论:

Powered by xia0yu