Merge pull request #885 from VakarisZ/timeouts

Added request timeouts
This commit is contained in:
VakarisZ 2020-11-16 15:17:41 +02:00 committed by GitHub
commit 5ba1bf1db8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 56 additions and 24 deletions

View File

@ -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.

View File

@ -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")

View File

@ -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.

View File

@ -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)

View File

@ -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')

View File

@ -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

View File

@ -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__)

View File

@ -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))

View File

@ -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: