Pocsuite3 POC/EXP编写

2021-10-11
3 min read

Pocsuite3 是一个POC框架,用于漏洞的验证、攻击等等

使用

https://github.com/knownsec/pocsuite3/blob/master/docs/USAGE.md

Pocsuite3可以进行批量验证、攻击,它有三种模式verify(验证)、attack(攻击)、shell(获得shell),并且可以设置多种参数。

编写POC

这里以CVE-2021-41773、CVE-2021-42013为例尝试使用Pocsuite3编写PoC与EXP:

思路:

分为linux与windows:

  • linux

发送post包检测是否可以RCE

如果不可以的话发送get包检测是否可以目录穿越

读取对象:/etc/passwd

关键字:root

  • windows

由于windows的apache无法直接调用cmd执行命令,只能通过php.exe之类的来解析,所以不考虑RCE,只判断是否可以目录穿越读取文件。

读取对象:c:/Windows/win.ini

关键字:extensions

由于两个RCE仅仅是URL编码的不同,所以这里直接使用二次URL编码来兼容两个RCE。

注意:python的request请求包会自动进行一次编码,所以编写poc的时候不需要二次编码

使用%2e即可

实验发现不行,它会在编码之前先解码一次,解码之后会将..删除,所以换了urllib库。

导入包

编写 PoC 实现类 DemoPOC,继承自 PoCBase

1
2
3
4
5
6
7
8
from pocsuite3.api import Output, POCBase, register_poc, requests, logger
from pocsuite3.api import get_listener_ip, get_listener_port
from pocsuite3.api import REVERSE_PAYLOAD
from pocsuite3.lib.utils import random_str

  class DemoPOC(POCBase):
    ...

PoC信息字段填写

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
    vulID = '0'  # ssvid ID 如果是提交漏洞的同时提交 PoC则写成 0
    version = '1.0'  # 默认为1
    author = 'Oulaa'  # PoC 作者的大名
    vulDate = '2021-10-5'  # 漏洞公开的时间不知道就写今天
    createDate = '2021-10-5'  # 编写 PoC 的日期
    updateDate = '2021-10-5'  # PoC 更新的时间默认和编写时间一样
    references = []  # 漏洞地址来源0day 不用写
    name = 'CVE-2021-41773/CVE-2021-42013 Apache HTTPd (2.4.49/2.4.50)'  # PoC 名称
    appPowerLink = 'Apache HTTPd'  # 漏洞厂商主页地址
    appName = 'Apache HTTPd'  # 漏洞应用名称
    appVersion = '2.4.49/2.4.50'  # 漏洞影响版本
    vulType = 'Path Traversal'  # 漏洞类型类型参考见漏洞类型规范表
    desc = '''
            Apache HTTPd 中间件2.4.49/2.4.50版本的目录穿越漏洞在开启了CGI的情况下可以做到RCE
        '''  # 漏洞简要描述
    samples = []  # 测试样列就是用 PoC 测试成功的网站
    install_requires = []  # PoC 第三方模块依赖请尽量不要使用第三方模块必要时请参考PoC第三方模块依赖说明填写
    pocDesc = ''' Apache HTTPd 2.4.49/2.4.50 验证是否存在目录穿越/RCE
    '''

验证模式编写

调用验证模式会进入_verify ,使用self.url 获得需要验证的url ,使用output.success(result)输出成功信息,使用output.fail 输出失败信息。

demo:

1
2
3
4
5
6
7
8
  def _verify(self):
        output = Output(self)
        # 验证代码
        if result:  # result是返回结果
            output.success(result)
        else:
            output.fail('target is not vulnerable')
        return output

注意:在_verify中我们常用新的函数 _check 来处理具体的验证逻辑,然后 使用_parse_output函数完成输出处理。例如在我们的poc中:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
    def _verify(self):
        result ={}
        apache = self._check(self.url)
        if apache:
            result['VerifyInfo'] = {}
            result['VerifyInfo']['URL'] = self.url
            result['VerifyInfo']['SYSTEM'] = apache[0]
            result['VerifyInfo']['TYPE'] = apache[1]
        return self.parse_output(result)
    def parse_output(self, result):
        output = Output(self)
        if result:
            output.success(result)
        else:
            output.fail('[-]target is not vulnerable')
        return output
    def _check(self, url):
	# return False
	return result


记录一下在编写CVE-2021-41773、CVE-2021-42013的_check 遇到的问题

  • 1.request 无法编码的问题: 使用urllib 库
  • 2.urllib库无法使用pocsuite3的proxy参数来代理: 使用它自己的proxy代理方式
  • 3.相关的python代码“urllib 库的使用”

编写攻击模式

_attack 模式与验证模式的编写方式差不多,但功能上更倾向于对目标进行 getshell,查询管理员帐号密码等操作。

1
2
3
4
def _attack(self):
    output = Output(self)
    result = {}
    # 攻击代码

如果不想定义该内容,return self._verify() 即可。

编写shell模式

pocsuite3 在 shell 模式会默认监听 6666 端口,编写对应的攻击代码,让目标执行反向连接运行 pocsuite3 系统 IP 的 6666 端口即可得到一个 shell

1
2
3
def _shell(self):
    cmd = REVERSE_PAYLOAD.BASH.format(get_listener_ip(), get_listener_port())
    # 攻击代码 execute cmd

shell 模式下,只能运行单个 PoC 脚本,控制台会进入 shell 交互模式执行命令及输出

返回内容

不管是验证模式或者攻击模式,返回结果 result 中的 key 值必须按照下面的规范来写

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
'Result':{
   'DBInfo' :   {'Username': 'xxx', 'Password': 'xxx', 'Salt': 'xxx' , 'Uid':'xxx' , 'Groupid':'xxx'},
   'ShellInfo': {'URL': 'xxx', 'Content': 'xxx' },
   'FileInfo':  {'Filename':'xxx','Content':'xxx'},
   'XSSInfo':   {'URL':'xxx','Payload':'xxx'},
   'AdminInfo': {'Uid':'xxx' , 'Username':'xxx' , 'Password':'xxx' }
   'Database':  {'Hostname':'xxx', 'Username':'xxx',  'Password':'xxx', 'DBname':'xxx'},
   'VerifyInfo':{'URL': 'xxx' , 'Postdata':'xxx' , 'Path':'xxx'}
   'SiteAttr':  {'Process':'xxx'}
   'Stdout': 'result output string'
}

POC中:

1
2
3
4
            result['VerifyInfo'] = {}
            result['VerifyInfo']['URL'] = self.url
            result['VerifyInfo']['SYSTEM'] = apache[0]
            result['VerifyInfo']['TYPE'] = apache[1]

自定义参数

如果你需要编写一个可以交互参数的 PoC 文件(例如有的 PoC 脚本需要填写登录信息,或者任意命令执行时执行任意命令),那么可以在 PoC 文件中声明一个 _options 方法。一个简单的例子如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
from collections import OrderedDict
from pocsuite3.api import Output, POCBase, POC_CATEGORY, register_poc, requests, VUL_TYPE
from pocsuite3.api import OptString
......

 def _options(self):
        o = OrderedDict()
        o["username"] = OptString('', description='这个poc需要用户登录请输入登录账号', require=True)
        o["password"] = OptString('', description='这个poc需要用户密码请输出用户密码', require=False)
        return o

PoC:

1
2
3
4
def _options(self):
        o = OrderedDict()
        o["cmd"] = OptString('', description='[+]请输入你想执行的命令', require=True)
        return o

总结:

简单使用了一下,感觉Pocsuite3来编写漏洞POC或者EXP还是比较方便的,还可以方便自定义插件,但是在使用了自定义参数后必须要使用这点比较不方便,没有找到解决方法可以让仅仅在某个模式才需要键入参数的方法。

代码地址:

https://github.com/Luoooio/allCode/blob/main/pocsuite3_pocs/CVE-2021-41773.py

参考文章

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

https://github.com/knownsec/pocsuite3/blob/master/docs/CODING.md#namedstandard

https://github.com/knownsec/pocsuite3/blob/master/docs/CODING.md#write_poc

Avatar
Oulaa 黑白之色,无间之守