commit
5ba1bf1db8
|
@ -4,6 +4,7 @@ import requests
|
||||||
|
|
||||||
from common.cloud.environment_names import Environment
|
from common.cloud.environment_names import Environment
|
||||||
from common.cloud.instance import CloudInstance
|
from common.cloud.instance import CloudInstance
|
||||||
|
from common.common_consts.timeouts import SHORT_REQUEST_TIMEOUT
|
||||||
|
|
||||||
LATEST_AZURE_METADATA_API_VERSION = "2019-04-30"
|
LATEST_AZURE_METADATA_API_VERSION = "2019-04-30"
|
||||||
AZURE_METADATA_SERVICE_URL = "http://169.254.169.254/metadata/instance?api-version=%s" % LATEST_AZURE_METADATA_API_VERSION
|
AZURE_METADATA_SERVICE_URL = "http://169.254.169.254/metadata/instance?api-version=%s" % LATEST_AZURE_METADATA_API_VERSION
|
||||||
|
@ -32,7 +33,9 @@ class AzureInstance(CloudInstance):
|
||||||
self.on_azure = False
|
self.on_azure = False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response = requests.get(AZURE_METADATA_SERVICE_URL, headers={"Metadata": "true"})
|
response = requests.get(AZURE_METADATA_SERVICE_URL,
|
||||||
|
headers={"Metadata": "true"},
|
||||||
|
timeout=SHORT_REQUEST_TIMEOUT)
|
||||||
self.on_azure = True
|
self.on_azure = True
|
||||||
|
|
||||||
# If not on cloud, the metadata URL is non-routable and the connection will fail.
|
# If not on cloud, the metadata URL is non-routable and the connection will fail.
|
||||||
|
|
|
@ -4,6 +4,7 @@ import requests
|
||||||
|
|
||||||
from common.cloud.environment_names import Environment
|
from common.cloud.environment_names import Environment
|
||||||
from common.cloud.instance import CloudInstance
|
from common.cloud.instance import CloudInstance
|
||||||
|
from common.common_consts.timeouts import SHORT_REQUEST_TIMEOUT
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -26,7 +27,7 @@ class GcpInstance(CloudInstance):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# If not on GCP, this domain shouldn't resolve.
|
# If not on GCP, this domain shouldn't resolve.
|
||||||
response = requests.get(GCP_METADATA_SERVICE_URL)
|
response = requests.get(GCP_METADATA_SERVICE_URL, timeout=SHORT_REQUEST_TIMEOUT)
|
||||||
|
|
||||||
if response:
|
if response:
|
||||||
logger.debug("Got ok metadata response: on GCP")
|
logger.debug("Got ok metadata response: on GCP")
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
SHORT_REQUEST_TIMEOUT = 2.5 # Seconds. Use where we expect timeout.
|
||||||
|
MEDIUM_REQUEST_TIMEOUT = 5 # Seconds. Use where we don't expect timeout.
|
||||||
|
LONG_REQUEST_TIMEOUT = 15 # Seconds. Use where we don't expect timeout and operate heavy data.
|
|
@ -9,6 +9,9 @@ from requests.exceptions import ConnectionError
|
||||||
|
|
||||||
import infection_monkey.monkeyfs as monkeyfs
|
import infection_monkey.monkeyfs as monkeyfs
|
||||||
import infection_monkey.tunnel as tunnel
|
import infection_monkey.tunnel as tunnel
|
||||||
|
from common.common_consts.timeouts import (LONG_REQUEST_TIMEOUT,
|
||||||
|
MEDIUM_REQUEST_TIMEOUT,
|
||||||
|
SHORT_REQUEST_TIMEOUT)
|
||||||
from common.data.api_url_consts import T1216_PBA_FILE_DOWNLOAD_PATH
|
from common.data.api_url_consts import T1216_PBA_FILE_DOWNLOAD_PATH
|
||||||
from infection_monkey.config import GUID, WormConfiguration
|
from infection_monkey.config import GUID, WormConfiguration
|
||||||
from infection_monkey.network.info import check_internet_access, local_ips
|
from infection_monkey.network.info import check_internet_access, local_ips
|
||||||
|
@ -121,7 +124,8 @@ class ControlClient(object):
|
||||||
data=json.dumps(monkey),
|
data=json.dumps(monkey),
|
||||||
headers={'content-type': 'application/json'},
|
headers={'content-type': 'application/json'},
|
||||||
verify=False,
|
verify=False,
|
||||||
proxies=ControlClient.proxies)
|
proxies=ControlClient.proxies,
|
||||||
|
timeout=MEDIUM_REQUEST_TIMEOUT)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
LOG.warning("Error connecting to control server %s: %s",
|
LOG.warning("Error connecting to control server %s: %s",
|
||||||
WormConfiguration.current_server, exc)
|
WormConfiguration.current_server, exc)
|
||||||
|
@ -138,7 +142,8 @@ class ControlClient(object):
|
||||||
data=json.dumps(telemetry),
|
data=json.dumps(telemetry),
|
||||||
headers={'content-type': 'application/json'},
|
headers={'content-type': 'application/json'},
|
||||||
verify=False,
|
verify=False,
|
||||||
proxies=ControlClient.proxies)
|
proxies=ControlClient.proxies,
|
||||||
|
timeout=MEDIUM_REQUEST_TIMEOUT)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
LOG.warning("Error connecting to control server %s: %s",
|
LOG.warning("Error connecting to control server %s: %s",
|
||||||
WormConfiguration.current_server, exc)
|
WormConfiguration.current_server, exc)
|
||||||
|
@ -153,7 +158,8 @@ class ControlClient(object):
|
||||||
data=json.dumps(telemetry),
|
data=json.dumps(telemetry),
|
||||||
headers={'content-type': 'application/json'},
|
headers={'content-type': 'application/json'},
|
||||||
verify=False,
|
verify=False,
|
||||||
proxies=ControlClient.proxies)
|
proxies=ControlClient.proxies,
|
||||||
|
timeout=MEDIUM_REQUEST_TIMEOUT)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
LOG.warning("Error connecting to control server %s: %s",
|
LOG.warning("Error connecting to control server %s: %s",
|
||||||
WormConfiguration.current_server, exc)
|
WormConfiguration.current_server, exc)
|
||||||
|
@ -165,7 +171,8 @@ class ControlClient(object):
|
||||||
try:
|
try:
|
||||||
reply = requests.get("https://%s/api/monkey/%s" % (WormConfiguration.current_server, GUID), # noqa: DUO123
|
reply = requests.get("https://%s/api/monkey/%s" % (WormConfiguration.current_server, GUID), # noqa: DUO123
|
||||||
verify=False,
|
verify=False,
|
||||||
proxies=ControlClient.proxies)
|
proxies=ControlClient.proxies,
|
||||||
|
timeout=MEDIUM_REQUEST_TIMEOUT)
|
||||||
|
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
LOG.warning("Error connecting to control server %s: %s",
|
LOG.warning("Error connecting to control server %s: %s",
|
||||||
|
@ -194,7 +201,8 @@ class ControlClient(object):
|
||||||
data=json.dumps({'config_error': True}),
|
data=json.dumps({'config_error': True}),
|
||||||
headers={'content-type': 'application/json'},
|
headers={'content-type': 'application/json'},
|
||||||
verify=False,
|
verify=False,
|
||||||
proxies=ControlClient.proxies)
|
proxies=ControlClient.proxies,
|
||||||
|
timeout=MEDIUM_REQUEST_TIMEOUT)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
LOG.warning("Error connecting to control server %s: %s", WormConfiguration.current_server, exc)
|
LOG.warning("Error connecting to control server %s: %s", WormConfiguration.current_server, exc)
|
||||||
return {}
|
return {}
|
||||||
|
@ -255,7 +263,8 @@ class ControlClient(object):
|
||||||
download = requests.get("https://%s/api/monkey/download/%s" % # noqa: DUO123
|
download = requests.get("https://%s/api/monkey/download/%s" % # noqa: DUO123
|
||||||
(WormConfiguration.current_server, filename),
|
(WormConfiguration.current_server, filename),
|
||||||
verify=False,
|
verify=False,
|
||||||
proxies=ControlClient.proxies)
|
proxies=ControlClient.proxies,
|
||||||
|
timeout=MEDIUM_REQUEST_TIMEOUT)
|
||||||
|
|
||||||
with monkeyfs.open(dest_file, 'wb') as file_obj:
|
with monkeyfs.open(dest_file, 'wb') as file_obj:
|
||||||
for chunk in download.iter_content(chunk_size=DOWNLOAD_CHUNK):
|
for chunk in download.iter_content(chunk_size=DOWNLOAD_CHUNK):
|
||||||
|
@ -281,7 +290,8 @@ class ControlClient(object):
|
||||||
reply = requests.post("https://%s/api/monkey/download" % (WormConfiguration.current_server,), # noqa: DUO123
|
reply = requests.post("https://%s/api/monkey/download" % (WormConfiguration.current_server,), # noqa: DUO123
|
||||||
data=json.dumps(host_dict),
|
data=json.dumps(host_dict),
|
||||||
headers={'content-type': 'application/json'},
|
headers={'content-type': 'application/json'},
|
||||||
verify=False, proxies=ControlClient.proxies)
|
verify=False, proxies=ControlClient.proxies,
|
||||||
|
timeout=LONG_REQUEST_TIMEOUT)
|
||||||
if 200 == reply.status_code:
|
if 200 == reply.status_code:
|
||||||
result_json = reply.json()
|
result_json = reply.json()
|
||||||
filename = result_json.get('filename')
|
filename = result_json.get('filename')
|
||||||
|
@ -323,7 +333,8 @@ class ControlClient(object):
|
||||||
return requests.get(PBA_FILE_DOWNLOAD % # noqa: DUO123
|
return requests.get(PBA_FILE_DOWNLOAD % # noqa: DUO123
|
||||||
(WormConfiguration.current_server, filename),
|
(WormConfiguration.current_server, filename),
|
||||||
verify=False,
|
verify=False,
|
||||||
proxies=ControlClient.proxies)
|
proxies=ControlClient.proxies,
|
||||||
|
timeout=LONG_REQUEST_TIMEOUT)
|
||||||
except requests.exceptions.RequestException:
|
except requests.exceptions.RequestException:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -334,7 +345,8 @@ class ControlClient(object):
|
||||||
T1216_PBA_FILE_DOWNLOAD_PATH),
|
T1216_PBA_FILE_DOWNLOAD_PATH),
|
||||||
verify=False,
|
verify=False,
|
||||||
proxies=ControlClient.proxies,
|
proxies=ControlClient.proxies,
|
||||||
stream=True)
|
stream=True,
|
||||||
|
timeout=MEDIUM_REQUEST_TIMEOUT)
|
||||||
except requests.exceptions.RequestException:
|
except requests.exceptions.RequestException:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -352,7 +364,7 @@ class ControlClient(object):
|
||||||
def can_island_see_port(port):
|
def can_island_see_port(port):
|
||||||
try:
|
try:
|
||||||
url = f"https://{WormConfiguration.current_server}/api/monkey_control/check_remote_port/{port}"
|
url = f"https://{WormConfiguration.current_server}/api/monkey_control/check_remote_port/{port}"
|
||||||
response = requests.get(url, verify=False)
|
response = requests.get(url, verify=False, timeout=SHORT_REQUEST_TIMEOUT)
|
||||||
response = json.loads(response.content.decode())
|
response = json.loads(response.content.decode())
|
||||||
return response['status'] == "port_visible"
|
return response['status'] == "port_visible"
|
||||||
except requests.exceptions.RequestException:
|
except requests.exceptions.RequestException:
|
||||||
|
@ -362,4 +374,5 @@ class ControlClient(object):
|
||||||
def report_start_on_island():
|
def report_start_on_island():
|
||||||
requests.post(f"https://{WormConfiguration.current_server}/api/monkey_control/started_on_island",
|
requests.post(f"https://{WormConfiguration.current_server}/api/monkey_control/started_on_island",
|
||||||
data=json.dumps({'started_on_island': True}),
|
data=json.dumps({'started_on_island': True}),
|
||||||
verify=False)
|
verify=False,
|
||||||
|
timeout=MEDIUM_REQUEST_TIMEOUT)
|
||||||
|
|
|
@ -9,6 +9,8 @@ from urllib.parse import urljoin
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
|
from common.common_consts.timeouts import (LONG_REQUEST_TIMEOUT,
|
||||||
|
MEDIUM_REQUEST_TIMEOUT)
|
||||||
from common.network.network_utils import remove_port
|
from common.network.network_utils import remove_port
|
||||||
from infection_monkey.exploit.web_rce import WebRCE
|
from infection_monkey.exploit.web_rce import WebRCE
|
||||||
from infection_monkey.model import ID_STRING
|
from infection_monkey.model import ID_STRING
|
||||||
|
@ -75,7 +77,8 @@ class DrupalExploiter(WebRCE):
|
||||||
response = requests.get(f'{url}?_format=hal_json', # noqa: DUO123
|
response = requests.get(f'{url}?_format=hal_json', # noqa: DUO123
|
||||||
json=payload,
|
json=payload,
|
||||||
headers={"Content-Type": "application/hal+json"},
|
headers={"Content-Type": "application/hal+json"},
|
||||||
verify=False)
|
verify=False,
|
||||||
|
timeout=MEDIUM_REQUEST_TIMEOUT)
|
||||||
|
|
||||||
if is_response_cached(response):
|
if is_response_cached(response):
|
||||||
LOG.info(f'Checking if node {url} is vuln returned cache HIT, ignoring')
|
LOG.info(f'Checking if node {url} is vuln returned cache HIT, ignoring')
|
||||||
|
@ -92,7 +95,8 @@ class DrupalExploiter(WebRCE):
|
||||||
r = requests.get(f'{url}?_format=hal_json', # noqa: DUO123
|
r = requests.get(f'{url}?_format=hal_json', # noqa: DUO123
|
||||||
json=payload,
|
json=payload,
|
||||||
headers={"Content-Type": "application/hal+json"},
|
headers={"Content-Type": "application/hal+json"},
|
||||||
verify=False)
|
verify=False,
|
||||||
|
timeout=LONG_REQUEST_TIMEOUT)
|
||||||
|
|
||||||
if is_response_cached(r):
|
if is_response_cached(r):
|
||||||
LOG.info(f'Exploiting {url} returned cache HIT, may have failed')
|
LOG.info(f'Exploiting {url} returned cache HIT, may have failed')
|
||||||
|
@ -136,7 +140,9 @@ def find_exploitbale_article_ids(base_url: str, lower: int = 1, upper: int = 100
|
||||||
articles = set()
|
articles = set()
|
||||||
while lower < upper:
|
while lower < upper:
|
||||||
node_url = urljoin(base_url, str(lower))
|
node_url = urljoin(base_url, str(lower))
|
||||||
response = requests.get(node_url, verify=False) # noqa: DUO123
|
response = requests.get(node_url,
|
||||||
|
verify=False,
|
||||||
|
timeout=LONG_REQUEST_TIMEOUT) # noqa: DUO123
|
||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
if is_response_cached(response):
|
if is_response_cached(response):
|
||||||
LOG.info(f'Found a cached article at: {node_url}, skipping')
|
LOG.info(f'Found a cached article at: {node_url}, skipping')
|
||||||
|
|
|
@ -11,6 +11,7 @@ import string
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
|
from common.common_consts.timeouts import LONG_REQUEST_TIMEOUT
|
||||||
from infection_monkey.exploit.tools.helpers import (build_monkey_commandline,
|
from infection_monkey.exploit.tools.helpers import (build_monkey_commandline,
|
||||||
get_monkey_depth)
|
get_monkey_depth)
|
||||||
from infection_monkey.exploit.tools.http_tools import HTTPTools
|
from infection_monkey.exploit.tools.http_tools import HTTPTools
|
||||||
|
@ -59,18 +60,20 @@ class HadoopExploiter(WebRCE):
|
||||||
|
|
||||||
def exploit(self, url, command):
|
def exploit(self, url, command):
|
||||||
# Get the newly created application id
|
# Get the newly created application id
|
||||||
resp = requests.post(posixpath.join(url, "ws/v1/cluster/apps/new-application"))
|
resp = requests.post(posixpath.join(url, "ws/v1/cluster/apps/new-application"),
|
||||||
|
timeout=LONG_REQUEST_TIMEOUT)
|
||||||
resp = json.loads(resp.content)
|
resp = json.loads(resp.content)
|
||||||
app_id = resp['application-id']
|
app_id = resp['application-id']
|
||||||
# Create a random name for our application in YARN
|
# Create a random name for our application in YARN
|
||||||
rand_name = ID_STRING + "".join([random.choice(string.ascii_lowercase) for _ in range(self.RAN_STR_LEN)])
|
rand_name = ID_STRING + "".join([random.choice(string.ascii_lowercase) for _ in range(self.RAN_STR_LEN)])
|
||||||
payload = self.build_payload(app_id, rand_name, command)
|
payload = self.build_payload(app_id, rand_name, command)
|
||||||
resp = requests.post(posixpath.join(url, "ws/v1/cluster/apps/"), json=payload)
|
resp = requests.post(posixpath.join(url, "ws/v1/cluster/apps/"), json=payload, timeout=LONG_REQUEST_TIMEOUT)
|
||||||
return resp.status_code == 202
|
return resp.status_code == 202
|
||||||
|
|
||||||
def check_if_exploitable(self, url):
|
def check_if_exploitable(self, url):
|
||||||
try:
|
try:
|
||||||
resp = requests.post(posixpath.join(url, "ws/v1/cluster/apps/new-application"))
|
resp = requests.post(posixpath.join(url, "ws/v1/cluster/apps/new-application"),
|
||||||
|
timeout=LONG_REQUEST_TIMEOUT)
|
||||||
except requests.ConnectionError:
|
except requests.ConnectionError:
|
||||||
return False
|
return False
|
||||||
return resp.status_code == 200
|
return resp.status_code == 200
|
||||||
|
|
|
@ -3,14 +3,11 @@ Implementation from https://github.com/SecuraBV/CVE-2020-1472
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import subprocess
|
|
||||||
|
|
||||||
import nmb.NetBIOS
|
import nmb.NetBIOS
|
||||||
from impacket.dcerpc.v5 import epm, nrpc, transport
|
from impacket.dcerpc.v5 import epm, nrpc, transport
|
||||||
|
|
||||||
import infection_monkey.config
|
|
||||||
from infection_monkey.network.HostFinger import HostFinger
|
from infection_monkey.network.HostFinger import HostFinger
|
||||||
from infection_monkey.utils.environment import is_windows_os
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ import requests
|
||||||
|
|
||||||
import infection_monkey.control
|
import infection_monkey.control
|
||||||
import infection_monkey.monkeyfs as monkeyfs
|
import infection_monkey.monkeyfs as monkeyfs
|
||||||
|
from common.common_consts.timeouts import SHORT_REQUEST_TIMEOUT
|
||||||
from infection_monkey.network.tools import get_interface_to_target
|
from infection_monkey.network.tools import get_interface_to_target
|
||||||
from infection_monkey.transport.base import (TransportProxyBase,
|
from infection_monkey.transport.base import (TransportProxyBase,
|
||||||
update_last_serve_time)
|
update_last_serve_time)
|
||||||
|
@ -123,7 +124,8 @@ class HTTPConnectProxyHandler(http.server.BaseHTTPRequestHandler):
|
||||||
r = requests.post(url=dest_path,
|
r = requests.post(url=dest_path,
|
||||||
data=post_data,
|
data=post_data,
|
||||||
verify=False,
|
verify=False,
|
||||||
proxies=infection_monkey.control.ControlClient.proxies)
|
proxies=infection_monkey.control.ControlClient.proxies,
|
||||||
|
timeout=SHORT_REQUEST_TIMEOUT)
|
||||||
self.send_response(r.status_code)
|
self.send_response(r.status_code)
|
||||||
except requests.exceptions.ConnectionError as e:
|
except requests.exceptions.ConnectionError as e:
|
||||||
LOG.error("Couldn't forward request to the island: {}".format(e))
|
LOG.error("Couldn't forward request to the island: {}".format(e))
|
||||||
|
|
|
@ -7,6 +7,7 @@ import pymongo
|
||||||
import requests
|
import requests
|
||||||
import urllib3
|
import urllib3
|
||||||
|
|
||||||
|
from common.common_consts.timeouts import SHORT_REQUEST_TIMEOUT
|
||||||
from monkey_island.cc.environment import Environment
|
from monkey_island.cc.environment import Environment
|
||||||
|
|
||||||
# Disable "unverified certificate" warnings when sending requests to island
|
# Disable "unverified certificate" warnings when sending requests to island
|
||||||
|
@ -32,7 +33,10 @@ class BootloaderHTTPRequestHandler(BaseHTTPRequestHandler):
|
||||||
# The island server doesn't always have a correct SSL cert installed
|
# The island server doesn't always have a correct SSL cert installed
|
||||||
# (By default it comes with a self signed one),
|
# (By default it comes with a self signed one),
|
||||||
# that's why we're not verifying the cert in this request.
|
# that's why we're not verifying the cert in this request.
|
||||||
r = requests.post(url=island_server_path, data=post_data, verify=False) # noqa: DUO123
|
r = requests.post(url=island_server_path,
|
||||||
|
data=post_data,
|
||||||
|
verify=False,
|
||||||
|
timeout=SHORT_REQUEST_TIMEOUT) # noqa: DUO123
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if r.status_code != 200:
|
if r.status_code != 200:
|
||||||
|
|
Loading…
Reference in New Issue