commit
c67ed63cc9
|
@ -19,6 +19,7 @@ repos:
|
||||||
rev: 3.9.1
|
rev: 3.9.1
|
||||||
hooks:
|
hooks:
|
||||||
- id: flake8
|
- id: flake8
|
||||||
|
additional_dependencies: [dlint]
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
rev: v3.4.0
|
rev: v3.4.0
|
||||||
hooks:
|
hooks:
|
||||||
|
|
|
@ -25,3 +25,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Attempted to delete a directory when monkey config reset was called. #1054
|
- Attempted to delete a directory when monkey config reset was called. #1054
|
||||||
|
|
||||||
|
### Security
|
||||||
|
- Address minor issues discovered by Dlint. #1075
|
||||||
|
|
|
@ -66,8 +66,8 @@ class MonkeyIslandRequests(object):
|
||||||
return request_function_wrapper
|
return request_function_wrapper
|
||||||
|
|
||||||
def get_jwt_from_server(self):
|
def get_jwt_from_server(self):
|
||||||
resp = requests.post(
|
resp = requests.post( # noqa: DUO123
|
||||||
self.addr + "api/auth", # noqa: DUO123
|
self.addr + "api/auth",
|
||||||
json={"username": NO_AUTH_CREDS, "password": NO_AUTH_CREDS},
|
json={"username": NO_AUTH_CREDS, "password": NO_AUTH_CREDS},
|
||||||
verify=False,
|
verify=False,
|
||||||
)
|
)
|
||||||
|
@ -75,8 +75,8 @@ class MonkeyIslandRequests(object):
|
||||||
|
|
||||||
@_Decorators.refresh_jwt_token
|
@_Decorators.refresh_jwt_token
|
||||||
def get(self, url, data=None):
|
def get(self, url, data=None):
|
||||||
return requests.get(
|
return requests.get( # noqa: DUO123
|
||||||
self.addr + url, # noqa: DUO123
|
self.addr + url,
|
||||||
headers=self.get_jwt_header(),
|
headers=self.get_jwt_header(),
|
||||||
params=data,
|
params=data,
|
||||||
verify=False,
|
verify=False,
|
||||||
|
@ -84,25 +84,25 @@ class MonkeyIslandRequests(object):
|
||||||
|
|
||||||
@_Decorators.refresh_jwt_token
|
@_Decorators.refresh_jwt_token
|
||||||
def post(self, url, data):
|
def post(self, url, data):
|
||||||
return requests.post(
|
return requests.post( # noqa: DUO123
|
||||||
self.addr + url, data=data, headers=self.get_jwt_header(), verify=False # noqa: DUO123
|
self.addr + url, data=data, headers=self.get_jwt_header(), verify=False
|
||||||
)
|
)
|
||||||
|
|
||||||
@_Decorators.refresh_jwt_token
|
@_Decorators.refresh_jwt_token
|
||||||
def post_json(self, url, data: Dict):
|
def post_json(self, url, data: Dict):
|
||||||
return requests.post(
|
return requests.post( # noqa: DUO123
|
||||||
self.addr + url, json=data, headers=self.get_jwt_header(), verify=False # noqa: DUO123
|
self.addr + url, json=data, headers=self.get_jwt_header(), verify=False
|
||||||
)
|
)
|
||||||
|
|
||||||
@_Decorators.refresh_jwt_token
|
@_Decorators.refresh_jwt_token
|
||||||
def patch(self, url, data: Dict):
|
def patch(self, url, data: Dict):
|
||||||
return requests.patch(
|
return requests.patch( # noqa: DUO123
|
||||||
self.addr + url, data=data, headers=self.get_jwt_header(), verify=False # noqa: DUO123
|
self.addr + url, data=data, headers=self.get_jwt_header(), verify=False
|
||||||
)
|
)
|
||||||
|
|
||||||
@_Decorators.refresh_jwt_token
|
@_Decorators.refresh_jwt_token
|
||||||
def delete(self, url):
|
def delete(self, url):
|
||||||
return requests.delete( # noqa: DOU123
|
return requests.delete( # noqa: DUO123
|
||||||
self.addr + url, headers=self.get_jwt_header(), verify=False
|
self.addr + url, headers=self.get_jwt_header(), verify=False
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -23,9 +23,9 @@ class GCPHandler(object):
|
||||||
subprocess.call(GCPHandler.get_auth_command(key_path), shell=True) # noqa: DUO116
|
subprocess.call(GCPHandler.get_auth_command(key_path), shell=True) # noqa: DUO116
|
||||||
LOGGER.info("GCP Handler passed key")
|
LOGGER.info("GCP Handler passed key")
|
||||||
# set project
|
# set project
|
||||||
subprocess.call(
|
subprocess.call( # noqa: DUO116
|
||||||
GCPHandler.get_set_project_command(project_id), shell=True
|
GCPHandler.get_set_project_command(project_id), shell=True
|
||||||
) # noqa: DUO116
|
)
|
||||||
LOGGER.info("GCP Handler set project")
|
LOGGER.info("GCP Handler set project")
|
||||||
LOGGER.info("GCP Handler initialized successfully")
|
LOGGER.info("GCP Handler initialized successfully")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -39,18 +39,18 @@ class GCPHandler(object):
|
||||||
"""
|
"""
|
||||||
LOGGER.info("Setting up all GCP machines...")
|
LOGGER.info("Setting up all GCP machines...")
|
||||||
try:
|
try:
|
||||||
subprocess.call(
|
subprocess.call( # noqa: DUO116
|
||||||
(GCPHandler.MACHINE_STARTING_COMMAND % (machine_list, self.zone)), shell=True
|
(GCPHandler.MACHINE_STARTING_COMMAND % (machine_list, self.zone)), shell=True
|
||||||
) # noqa: DUO116
|
)
|
||||||
LOGGER.info("GCP machines successfully started.")
|
LOGGER.info("GCP machines successfully started.")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
LOGGER.error("GCP Handler failed to start GCP machines: %s" % e)
|
LOGGER.error("GCP Handler failed to start GCP machines: %s" % e)
|
||||||
|
|
||||||
def stop_machines(self, machine_list):
|
def stop_machines(self, machine_list):
|
||||||
try:
|
try:
|
||||||
subprocess.call(
|
subprocess.call( # noqa: DUO116
|
||||||
(GCPHandler.MACHINE_STOPPING_COMMAND % (machine_list, self.zone)), shell=True
|
(GCPHandler.MACHINE_STOPPING_COMMAND % (machine_list, self.zone)), shell=True
|
||||||
) # noqa: DUO116
|
)
|
||||||
LOGGER.info("GCP machines stopped successfully.")
|
LOGGER.info("GCP machines stopped successfully.")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
LOGGER.error("GCP Handler failed to stop network machines: %s" % e)
|
LOGGER.error("GCP Handler failed to stop network machines: %s" % e)
|
||||||
|
|
|
@ -64,8 +64,8 @@ class ControlClient(object):
|
||||||
if ControlClient.proxies:
|
if ControlClient.proxies:
|
||||||
monkey["tunnel"] = ControlClient.proxies.get("https")
|
monkey["tunnel"] = ControlClient.proxies.get("https")
|
||||||
|
|
||||||
requests.post(
|
requests.post( # noqa: DUO123
|
||||||
"https://%s/api/monkey" % (WormConfiguration.current_server,), # noqa: DUO123
|
"https://%s/api/monkey" % (WormConfiguration.current_server,),
|
||||||
data=json.dumps(monkey),
|
data=json.dumps(monkey),
|
||||||
headers={"content-type": "application/json"},
|
headers={"content-type": "application/json"},
|
||||||
verify=False,
|
verify=False,
|
||||||
|
@ -92,8 +92,8 @@ class ControlClient(object):
|
||||||
if ControlClient.proxies:
|
if ControlClient.proxies:
|
||||||
debug_message += " through proxies: %s" % ControlClient.proxies
|
debug_message += " through proxies: %s" % ControlClient.proxies
|
||||||
LOG.debug(debug_message)
|
LOG.debug(debug_message)
|
||||||
requests.get(
|
requests.get( # noqa: DUO123
|
||||||
f"https://{server}/api?action=is-up", # noqa: DUO123
|
f"https://{server}/api?action=is-up",
|
||||||
verify=False,
|
verify=False,
|
||||||
proxies=ControlClient.proxies,
|
proxies=ControlClient.proxies,
|
||||||
timeout=TIMEOUT_IN_SECONDS,
|
timeout=TIMEOUT_IN_SECONDS,
|
||||||
|
@ -130,9 +130,8 @@ class ControlClient(object):
|
||||||
monkey = {}
|
monkey = {}
|
||||||
if ControlClient.proxies:
|
if ControlClient.proxies:
|
||||||
monkey["tunnel"] = ControlClient.proxies.get("https")
|
monkey["tunnel"] = ControlClient.proxies.get("https")
|
||||||
requests.patch(
|
requests.patch( # noqa: DUO123
|
||||||
"https://%s/api/monkey/%s"
|
"https://%s/api/monkey/%s" % (WormConfiguration.current_server, GUID),
|
||||||
% (WormConfiguration.current_server, GUID), # noqa: DUO123
|
|
||||||
data=json.dumps(monkey),
|
data=json.dumps(monkey),
|
||||||
headers={"content-type": "application/json"},
|
headers={"content-type": "application/json"},
|
||||||
verify=False,
|
verify=False,
|
||||||
|
@ -155,8 +154,8 @@ class ControlClient(object):
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
telemetry = {"monkey_guid": GUID, "telem_category": telem_category, "data": json_data}
|
telemetry = {"monkey_guid": GUID, "telem_category": telem_category, "data": json_data}
|
||||||
requests.post(
|
requests.post( # noqa: DUO123
|
||||||
"https://%s/api/telemetry" % (WormConfiguration.current_server,), # noqa: DUO123
|
"https://%s/api/telemetry" % (WormConfiguration.current_server,),
|
||||||
data=json.dumps(telemetry),
|
data=json.dumps(telemetry),
|
||||||
headers={"content-type": "application/json"},
|
headers={"content-type": "application/json"},
|
||||||
verify=False,
|
verify=False,
|
||||||
|
@ -174,8 +173,8 @@ class ControlClient(object):
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
telemetry = {"monkey_guid": GUID, "log": json.dumps(log)}
|
telemetry = {"monkey_guid": GUID, "log": json.dumps(log)}
|
||||||
requests.post(
|
requests.post( # noqa: DUO123
|
||||||
"https://%s/api/log" % (WormConfiguration.current_server,), # noqa: DUO123
|
"https://%s/api/log" % (WormConfiguration.current_server,),
|
||||||
data=json.dumps(telemetry),
|
data=json.dumps(telemetry),
|
||||||
headers={"content-type": "application/json"},
|
headers={"content-type": "application/json"},
|
||||||
verify=False,
|
verify=False,
|
||||||
|
@ -192,9 +191,8 @@ class ControlClient(object):
|
||||||
if not WormConfiguration.current_server:
|
if not WormConfiguration.current_server:
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
reply = requests.get(
|
reply = requests.get( # noqa: DUO123
|
||||||
"https://%s/api/monkey/%s"
|
"https://%s/api/monkey/%s" % (WormConfiguration.current_server, GUID),
|
||||||
% (WormConfiguration.current_server, GUID), # noqa: DUO123
|
|
||||||
verify=False,
|
verify=False,
|
||||||
proxies=ControlClient.proxies,
|
proxies=ControlClient.proxies,
|
||||||
timeout=MEDIUM_REQUEST_TIMEOUT,
|
timeout=MEDIUM_REQUEST_TIMEOUT,
|
||||||
|
@ -230,9 +228,8 @@ class ControlClient(object):
|
||||||
if not WormConfiguration.current_server:
|
if not WormConfiguration.current_server:
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
requests.patch(
|
requests.patch( # noqa: DUO123
|
||||||
"https://%s/api/monkey/%s"
|
"https://%s/api/monkey/%s" % (WormConfiguration.current_server, GUID),
|
||||||
% (WormConfiguration.current_server, GUID), # noqa: DUO123
|
|
||||||
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,
|
||||||
|
@ -292,9 +289,9 @@ class ControlClient(object):
|
||||||
if (monkeyfs.isfile(dest_file)) and (size == monkeyfs.getsize(dest_file)):
|
if (monkeyfs.isfile(dest_file)) and (size == monkeyfs.getsize(dest_file)):
|
||||||
return dest_file
|
return dest_file
|
||||||
else:
|
else:
|
||||||
download = requests.get(
|
download = requests.get( # noqa: DUO123
|
||||||
"https://%s/api/monkey/download/%s"
|
"https://%s/api/monkey/download/%s"
|
||||||
% (WormConfiguration.current_server, filename), # noqa: DUO123
|
% (WormConfiguration.current_server, filename),
|
||||||
verify=False,
|
verify=False,
|
||||||
proxies=ControlClient.proxies,
|
proxies=ControlClient.proxies,
|
||||||
timeout=MEDIUM_REQUEST_TIMEOUT,
|
timeout=MEDIUM_REQUEST_TIMEOUT,
|
||||||
|
@ -322,9 +319,8 @@ class ControlClient(object):
|
||||||
if not WormConfiguration.current_server:
|
if not WormConfiguration.current_server:
|
||||||
return None, None
|
return None, None
|
||||||
try:
|
try:
|
||||||
reply = requests.post(
|
reply = requests.post( # noqa: DUO123
|
||||||
"https://%s/api/monkey/download"
|
"https://%s/api/monkey/download" % (WormConfiguration.current_server,),
|
||||||
% (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,
|
verify=False,
|
||||||
|
@ -370,8 +366,8 @@ class ControlClient(object):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_pba_file(filename):
|
def get_pba_file(filename):
|
||||||
try:
|
try:
|
||||||
return requests.get(
|
return requests.get( # noqa: DUO123
|
||||||
PBA_FILE_DOWNLOAD % (WormConfiguration.current_server, filename), # noqa: DUO123
|
PBA_FILE_DOWNLOAD % (WormConfiguration.current_server, filename),
|
||||||
verify=False,
|
verify=False,
|
||||||
proxies=ControlClient.proxies,
|
proxies=ControlClient.proxies,
|
||||||
timeout=LONG_REQUEST_TIMEOUT,
|
timeout=LONG_REQUEST_TIMEOUT,
|
||||||
|
@ -382,9 +378,9 @@ class ControlClient(object):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_T1216_pba_file():
|
def get_T1216_pba_file():
|
||||||
try:
|
try:
|
||||||
return requests.get(
|
return requests.get( # noqa: DUO123
|
||||||
urljoin(
|
urljoin(
|
||||||
f"https://{WormConfiguration.current_server}/", # noqa: DUO123
|
f"https://{WormConfiguration.current_server}/",
|
||||||
T1216_PBA_FILE_DOWNLOAD_PATH,
|
T1216_PBA_FILE_DOWNLOAD_PATH,
|
||||||
),
|
),
|
||||||
verify=False,
|
verify=False,
|
||||||
|
@ -416,7 +412,9 @@ class ControlClient(object):
|
||||||
f"https://{WormConfiguration.current_server}/api/monkey_control"
|
f"https://{WormConfiguration.current_server}/api/monkey_control"
|
||||||
f"/check_remote_port/{port}"
|
f"/check_remote_port/{port}"
|
||||||
)
|
)
|
||||||
response = requests.get(url, verify=False, timeout=SHORT_REQUEST_TIMEOUT)
|
response = requests.get( # noqa: DUO123
|
||||||
|
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:
|
||||||
|
@ -424,7 +422,7 @@ class ControlClient(object):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def report_start_on_island():
|
def report_start_on_island():
|
||||||
requests.post(
|
requests.post( # noqa: DUO123
|
||||||
f"https://{WormConfiguration.current_server}/api/monkey_control/started_on_island",
|
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,
|
||||||
|
|
|
@ -4,6 +4,7 @@ import filecmp
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import pprint
|
import pprint
|
||||||
|
import shlex
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
@ -13,11 +14,7 @@ from ctypes import c_char_p
|
||||||
from common.utils.attack_utils import ScanStatus, UsageEnum
|
from common.utils.attack_utils import ScanStatus, UsageEnum
|
||||||
from infection_monkey.config import WormConfiguration
|
from infection_monkey.config import WormConfiguration
|
||||||
from infection_monkey.exploit.tools.helpers import build_monkey_commandline_explicitly
|
from infection_monkey.exploit.tools.helpers import build_monkey_commandline_explicitly
|
||||||
from infection_monkey.model import (
|
from infection_monkey.model import MONKEY_CMDLINE_LINUX, MONKEY_CMDLINE_WINDOWS
|
||||||
GENERAL_CMDLINE_LINUX,
|
|
||||||
MONKEY_CMDLINE_LINUX,
|
|
||||||
MONKEY_CMDLINE_WINDOWS,
|
|
||||||
)
|
|
||||||
from infection_monkey.system_info import OperatingSystem, SystemInfoCollector
|
from infection_monkey.system_info import OperatingSystem, SystemInfoCollector
|
||||||
from infection_monkey.telemetry.attack.t1106_telem import T1106Telem
|
from infection_monkey.telemetry.attack.t1106_telem import T1106Telem
|
||||||
|
|
||||||
|
@ -146,33 +143,46 @@ class MonkeyDrops(object):
|
||||||
)
|
)
|
||||||
|
|
||||||
if OperatingSystem.Windows == SystemInfoCollector.get_os():
|
if OperatingSystem.Windows == SystemInfoCollector.get_os():
|
||||||
|
# TODO: Replace all of this string templating with a function that accepts
|
||||||
|
# the necessary parameters and returns a list of arguments.
|
||||||
monkey_cmdline = (
|
monkey_cmdline = (
|
||||||
MONKEY_CMDLINE_WINDOWS % {"monkey_path": self._config["destination_path"]}
|
MONKEY_CMDLINE_WINDOWS % {"monkey_path": self._config["destination_path"]}
|
||||||
+ monkey_options
|
+ monkey_options
|
||||||
)
|
)
|
||||||
|
monkey_cmdline_split = shlex.split(
|
||||||
|
monkey_cmdline,
|
||||||
|
posix=False, # won't try resolving "\" in paths as part of escape sequences
|
||||||
|
)
|
||||||
|
|
||||||
|
monkey_process = subprocess.Popen(
|
||||||
|
monkey_cmdline_split,
|
||||||
|
stdin=subprocess.PIPE,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE,
|
||||||
|
close_fds=True,
|
||||||
|
creationflags=DETACHED_PROCESS,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
dest_path = self._config["destination_path"]
|
dest_path = self._config["destination_path"]
|
||||||
# In linux we have a more complex commandline. There's a general outer one,
|
# In Linux, we need to change the directory first, which is done
|
||||||
# and the inner one which actually
|
# using thw `cwd` argument in `subprocess.Popen` below
|
||||||
# runs the monkey
|
# TODO: Replace all of this string templating with a function that accepts
|
||||||
inner_monkey_cmdline = (
|
# the necessary parameters and returns a list of arguments.
|
||||||
|
monkey_cmdline = (
|
||||||
MONKEY_CMDLINE_LINUX % {"monkey_filename": dest_path.split("/")[-1]}
|
MONKEY_CMDLINE_LINUX % {"monkey_filename": dest_path.split("/")[-1]}
|
||||||
+ monkey_options
|
+ monkey_options
|
||||||
)
|
)
|
||||||
monkey_cmdline = GENERAL_CMDLINE_LINUX % {
|
monkey_cmdline_split = shlex.split(monkey_cmdline)
|
||||||
"monkey_directory": dest_path[0 : dest_path.rfind("/")],
|
|
||||||
"monkey_commandline": inner_monkey_cmdline,
|
|
||||||
}
|
|
||||||
|
|
||||||
monkey_process = subprocess.Popen(
|
monkey_process = subprocess.Popen(
|
||||||
monkey_cmdline,
|
monkey_cmdline_split,
|
||||||
shell=True,
|
stdin=subprocess.PIPE,
|
||||||
stdin=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
stdout=subprocess.PIPE,
|
stderr=subprocess.PIPE,
|
||||||
stderr=subprocess.PIPE,
|
close_fds=True,
|
||||||
close_fds=True,
|
cwd="/".join(dest_path.split("/")[0:-1]),
|
||||||
creationflags=DETACHED_PROCESS,
|
creationflags=DETACHED_PROCESS,
|
||||||
)
|
)
|
||||||
|
|
||||||
LOG.info(
|
LOG.info(
|
||||||
"Executed monkey process (PID=%d) with command line: %s",
|
"Executed monkey process (PID=%d) with command line: %s",
|
||||||
|
|
|
@ -82,8 +82,8 @@ class DrupalExploiter(WebRCE):
|
||||||
"""
|
"""
|
||||||
payload = build_exploitability_check_payload(url)
|
payload = build_exploitability_check_payload(url)
|
||||||
|
|
||||||
response = requests.get(
|
response = requests.get( # noqa: DUO123
|
||||||
f"{url}?_format=hal_json", # noqa: DUO123
|
f"{url}?_format=hal_json",
|
||||||
json=payload,
|
json=payload,
|
||||||
headers={"Content-Type": "application/hal+json"},
|
headers={"Content-Type": "application/hal+json"},
|
||||||
verify=False,
|
verify=False,
|
||||||
|
@ -102,8 +102,8 @@ class DrupalExploiter(WebRCE):
|
||||||
base = remove_port(url)
|
base = remove_port(url)
|
||||||
payload = build_cmd_execution_payload(base, cmd)
|
payload = build_cmd_execution_payload(base, cmd)
|
||||||
|
|
||||||
r = requests.get(
|
r = requests.get( # noqa: DUO123
|
||||||
f"{url}?_format=hal_json", # noqa: DUO123
|
f"{url}?_format=hal_json",
|
||||||
json=payload,
|
json=payload,
|
||||||
headers={"Content-Type": "application/hal+json"},
|
headers={"Content-Type": "application/hal+json"},
|
||||||
verify=False,
|
verify=False,
|
||||||
|
@ -157,9 +157,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(
|
response = requests.get( # noqa: DUO123
|
||||||
node_url, verify=False, timeout=LONG_REQUEST_TIMEOUT
|
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")
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import posixpath
|
import posixpath
|
||||||
import random
|
|
||||||
import string
|
import string
|
||||||
|
from random import SystemRandom
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
|
@ -69,8 +69,9 @@ class HadoopExploiter(WebRCE):
|
||||||
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
|
||||||
|
safe_random = SystemRandom()
|
||||||
rand_name = ID_STRING + "".join(
|
rand_name = ID_STRING + "".join(
|
||||||
[random.choice(string.ascii_lowercase) for _ in range(self.RAN_STR_LEN)]
|
[safe_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(
|
resp = requests.post(
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import string
|
import string
|
||||||
from random import choice
|
from random import SystemRandom
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
|
@ -37,8 +37,9 @@ class ShellShockExploiter(HostExploiter):
|
||||||
def __init__(self, host):
|
def __init__(self, host):
|
||||||
super(ShellShockExploiter, self).__init__(host)
|
super(ShellShockExploiter, self).__init__(host)
|
||||||
self.HTTP = [str(port) for port in self._config.HTTP_PORTS]
|
self.HTTP = [str(port) for port in self._config.HTTP_PORTS]
|
||||||
|
safe_random = SystemRandom()
|
||||||
self.success_flag = "".join(
|
self.success_flag = "".join(
|
||||||
choice(string.ascii_uppercase + string.digits) for _ in range(20)
|
safe_random.choice(string.ascii_uppercase + string.digits) for _ in range(20)
|
||||||
)
|
)
|
||||||
self.skip_exist = self._config.skip_exploit_if_file_exist
|
self.skip_exist = self._config.skip_exploit_if_file_exist
|
||||||
|
|
||||||
|
@ -242,9 +243,9 @@ class ShellShockExploiter(HostExploiter):
|
||||||
try:
|
try:
|
||||||
LOG.debug("Header is: %s" % header)
|
LOG.debug("Header is: %s" % header)
|
||||||
LOG.debug("Attack is: %s" % attack)
|
LOG.debug("Attack is: %s" % attack)
|
||||||
r = requests.get(
|
r = requests.get( # noqa: DUO123
|
||||||
url, headers={header: attack}, verify=False, timeout=TIMEOUT
|
url, headers={header: attack}, verify=False, timeout=TIMEOUT
|
||||||
) # noqa: DUO123
|
)
|
||||||
result = r.content.decode()
|
result = r.content.decode()
|
||||||
return result
|
return result
|
||||||
except requests.exceptions.RequestException as exc:
|
except requests.exceptions.RequestException as exc:
|
||||||
|
|
|
@ -52,7 +52,7 @@ class Struts2Exploiter(WebRCE):
|
||||||
request = urllib.request.Request(url, headers=headers)
|
request = urllib.request.Request(url, headers=headers)
|
||||||
try:
|
try:
|
||||||
return urllib.request.urlopen(
|
return urllib.request.urlopen(
|
||||||
request, context=ssl._create_unverified_context()
|
request, context=ssl._create_unverified_context() # noqa: DUO122
|
||||||
).geturl()
|
).geturl()
|
||||||
except urllib.error.URLError:
|
except urllib.error.URLError:
|
||||||
LOG.error("Can't reach struts2 server")
|
LOG.error("Can't reach struts2 server")
|
||||||
|
|
|
@ -83,9 +83,9 @@ class WebLogic201710271(WebRCE):
|
||||||
else:
|
else:
|
||||||
payload = self.get_exploit_payload("cmd", "/c", command + " 1> NUL 2> NUL")
|
payload = self.get_exploit_payload("cmd", "/c", command + " 1> NUL 2> NUL")
|
||||||
try:
|
try:
|
||||||
post(
|
post( # noqa: DUO123
|
||||||
url, data=payload, headers=HEADERS, timeout=EXECUTION_TIMEOUT, verify=False
|
url, data=payload, headers=HEADERS, timeout=EXECUTION_TIMEOUT, verify=False
|
||||||
) # noqa: DUO123
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
LOG.error("Connection error: %s" % e)
|
LOG.error("Connection error: %s" % e)
|
||||||
return False
|
return False
|
||||||
|
@ -121,9 +121,9 @@ class WebLogic201710271(WebRCE):
|
||||||
def check_if_exploitable_weblogic(self, url, httpd):
|
def check_if_exploitable_weblogic(self, url, httpd):
|
||||||
payload = self.get_test_payload(ip=httpd.local_ip, port=httpd.local_port)
|
payload = self.get_test_payload(ip=httpd.local_ip, port=httpd.local_port)
|
||||||
try:
|
try:
|
||||||
post(
|
post( # noqa: DUO123
|
||||||
url, data=payload, headers=HEADERS, timeout=REQUEST_DELAY, verify=False
|
url, data=payload, headers=HEADERS, timeout=REQUEST_DELAY, verify=False
|
||||||
) # noqa: DUO123
|
)
|
||||||
except exceptions.ReadTimeout:
|
except exceptions.ReadTimeout:
|
||||||
# Our request will not get response thus we get ReadTimeout error
|
# Our request will not get response thus we get ReadTimeout error
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import itertools
|
import itertools
|
||||||
import socket
|
import socket
|
||||||
import struct
|
import struct
|
||||||
from random import randint
|
from random import randint # noqa: DUO102
|
||||||
from subprocess import check_output
|
from subprocess import check_output
|
||||||
|
|
||||||
import netifaces
|
import netifaces
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from itertools import zip_longest
|
from itertools import zip_longest
|
||||||
from random import shuffle
|
from random import shuffle # noqa: DUO102
|
||||||
|
|
||||||
import infection_monkey.config
|
import infection_monkey.config
|
||||||
from infection_monkey.network.HostFinger import HostFinger
|
from infection_monkey.network.HostFinger import HostFinger
|
||||||
|
|
|
@ -46,8 +46,8 @@ class ClearCommandHistory(PBA):
|
||||||
def run(self):
|
def run(self):
|
||||||
if self.command:
|
if self.command:
|
||||||
try:
|
try:
|
||||||
output = subprocess.check_output(
|
output = subprocess.check_output( # noqa: DUO116
|
||||||
self.command, stderr=subprocess.STDOUT, shell=True # noqa: DUO116
|
self.command, stderr=subprocess.STDOUT, shell=True
|
||||||
).decode()
|
).decode()
|
||||||
return output, True
|
return output, True
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
|
|
|
@ -52,8 +52,8 @@ class CommunicateAsNewUser(PBA):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_random_new_user_name():
|
def get_random_new_user_name():
|
||||||
return USERNAME_PREFIX + "".join(
|
return USERNAME_PREFIX + "".join(
|
||||||
random.choice(string.ascii_lowercase) for _ in range(5)
|
random.choice(string.ascii_lowercase) for _ in range(5) # noqa: DUO102
|
||||||
) # noqa: DUO102
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_commandline_for_http_request(url, is_windows=is_windows_os()):
|
def get_commandline_for_http_request(url, is_windows=is_windows_os()):
|
||||||
|
|
|
@ -58,8 +58,8 @@ class ModifyShellStartupFiles(PBA):
|
||||||
def run(self):
|
def run(self):
|
||||||
if self.command:
|
if self.command:
|
||||||
try:
|
try:
|
||||||
output = subprocess.check_output(
|
output = subprocess.check_output( # noqa: DUO116
|
||||||
self.command, stderr=subprocess.STDOUT, shell=True # noqa: DUO116
|
self.command, stderr=subprocess.STDOUT, shell=True
|
||||||
).decode()
|
).decode()
|
||||||
return output, True
|
return output, True
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
|
|
|
@ -21,10 +21,9 @@ class SignedScriptProxyExecution(PBA):
|
||||||
try:
|
try:
|
||||||
original_comspec = ""
|
original_comspec = ""
|
||||||
if is_windows_os():
|
if is_windows_os():
|
||||||
original_comspec = subprocess.check_output(
|
original_comspec = subprocess.check_output( # noqa: DUO116
|
||||||
"if defined COMSPEC echo %COMSPEC%", shell=True
|
"if defined COMSPEC echo %COMSPEC%", shell=True
|
||||||
).decode() # noqa: DUO116
|
).decode()
|
||||||
|
|
||||||
super().run()
|
super().run()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
LOG.warning(
|
LOG.warning(
|
||||||
|
|
|
@ -90,7 +90,7 @@ class PBA(Plugin):
|
||||||
:return: Tuple of command's output string and boolean, indicating if it succeeded
|
:return: Tuple of command's output string and boolean, indicating if it succeeded
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
output = subprocess.check_output(
|
output = subprocess.check_output( # noqa: DUO116
|
||||||
self.command, stderr=subprocess.STDOUT, shell=True
|
self.command, stderr=subprocess.STDOUT, shell=True
|
||||||
).decode()
|
).decode()
|
||||||
return output, True
|
return output, True
|
||||||
|
|
|
@ -13,8 +13,10 @@ def get_windows_commands_to_modify_shell_startup_files():
|
||||||
|
|
||||||
# get list of usernames
|
# get list of usernames
|
||||||
USERS = (
|
USERS = (
|
||||||
subprocess.check_output("dir C:\\Users /b", shell=True).decode().split("\r\n")[:-1]
|
subprocess.check_output("dir C:\\Users /b", shell=True) # noqa: DUO116
|
||||||
) # noqa: DUO116
|
.decode()
|
||||||
|
.split("\r\n")[:-1]
|
||||||
|
)
|
||||||
USERS.remove("Public")
|
USERS.remove("Public")
|
||||||
|
|
||||||
STARTUP_FILES_PER_USER = [
|
STARTUP_FILES_PER_USER = [
|
||||||
|
|
|
@ -15,7 +15,7 @@ def get_commands_to_proxy_execution_using_signed_script():
|
||||||
|
|
||||||
def cleanup_changes(original_comspec):
|
def cleanup_changes(original_comspec):
|
||||||
if is_windows_os():
|
if is_windows_os():
|
||||||
subprocess.run(
|
subprocess.run( # noqa: DUO116
|
||||||
get_windows_commands_to_reset_comspec(original_comspec), shell=True
|
get_windows_commands_to_reset_comspec(original_comspec), shell=True
|
||||||
) # noqa: DUO116
|
)
|
||||||
subprocess.run(get_windows_commands_to_delete_temp_comspec(), shell=True) # noqa: DUO116
|
subprocess.run(get_windows_commands_to_delete_temp_comspec(), shell=True) # noqa: DUO116
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import logging
|
import logging
|
||||||
|
import shlex
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
@ -51,10 +52,10 @@ class WindowsInfoCollector(InfoCollector):
|
||||||
def get_installed_packages(self):
|
def get_installed_packages(self):
|
||||||
LOG.info("Getting installed packages")
|
LOG.info("Getting installed packages")
|
||||||
|
|
||||||
packages = subprocess.check_output("dism /online /get-packages", shell=True)
|
packages = subprocess.check_output(shlex.split("dism /online /get-packages"))
|
||||||
self.info["installed_packages"] = packages.decode("utf-8", errors="ignore")
|
self.info["installed_packages"] = packages.decode("utf-8", errors="ignore")
|
||||||
|
|
||||||
features = subprocess.check_output("dism /online /get-features", shell=True)
|
features = subprocess.check_output(shlex.split("dism /online /get-features"))
|
||||||
self.info["installed_features"] = features.decode("utf-8", errors="ignore")
|
self.info["installed_features"] = features.decode("utf-8", errors="ignore")
|
||||||
|
|
||||||
LOG.debug("Got installed packages")
|
LOG.debug("Got installed packages")
|
||||||
|
|
|
@ -126,7 +126,7 @@ class HTTPConnectProxyHandler(http.server.BaseHTTPRequestHandler):
|
||||||
LOG.info("Received bootloader's request: {}".format(post_data))
|
LOG.info("Received bootloader's request: {}".format(post_data))
|
||||||
try:
|
try:
|
||||||
dest_path = self.path
|
dest_path = self.path
|
||||||
r = requests.post(
|
r = requests.post( # noqa: DUO123
|
||||||
url=dest_path,
|
url=dest_path,
|
||||||
data=post_data,
|
data=post_data,
|
||||||
verify=False,
|
verify=False,
|
||||||
|
|
|
@ -26,9 +26,9 @@ def get_commands_to_hide_folders():
|
||||||
|
|
||||||
|
|
||||||
def cleanup_hidden_files(is_windows=is_windows_os()):
|
def cleanup_hidden_files(is_windows=is_windows_os()):
|
||||||
subprocess.run(
|
subprocess.run( # noqa: DUO116
|
||||||
get_windows_commands_to_delete()
|
get_windows_commands_to_delete()
|
||||||
if is_windows # noqa: DUO116
|
if is_windows
|
||||||
else " ".join(get_linux_commands_to_delete()),
|
else " ".join(get_linux_commands_to_delete()),
|
||||||
shell=True,
|
shell=True,
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import datetime
|
import datetime
|
||||||
import logging
|
import logging
|
||||||
import os
|
import shlex
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
from infection_monkey.utils.auto_new_user import AutoNewUser
|
from infection_monkey.utils.auto_new_user import AutoNewUser
|
||||||
|
@ -43,18 +43,16 @@ class AutoNewLinuxUser(AutoNewUser):
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"Trying to add {} with commands {}".format(self.username, str(commands_to_add_user))
|
"Trying to add {} with commands {}".format(self.username, str(commands_to_add_user))
|
||||||
)
|
)
|
||||||
_ = subprocess.check_output(
|
_ = subprocess.check_output(commands_to_add_user, stderr=subprocess.STDOUT)
|
||||||
" ".join(commands_to_add_user), stderr=subprocess.STDOUT, shell=True
|
|
||||||
)
|
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
return self # No initialization/logging on needed in Linux
|
return self # No initialization/logging on needed in Linux
|
||||||
|
|
||||||
def run_as(self, command):
|
def run_as(self, command):
|
||||||
command_as_new_user = "sudo -u {username} {command}".format(
|
command_as_new_user = shlex.split(
|
||||||
username=self.username, command=command
|
"sudo -u {username} {command}".format(username=self.username, command=command)
|
||||||
)
|
)
|
||||||
return os.system(command_as_new_user)
|
return subprocess.call(command_as_new_user)
|
||||||
|
|
||||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||||
# delete the user.
|
# delete the user.
|
||||||
|
@ -64,6 +62,4 @@ class AutoNewLinuxUser(AutoNewUser):
|
||||||
self.username, str(commands_to_delete_user)
|
self.username, str(commands_to_delete_user)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
_ = subprocess.check_output(
|
_ = subprocess.check_output(commands_to_delete_user, stderr=subprocess.STDOUT)
|
||||||
" ".join(commands_to_delete_user), stderr=subprocess.STDOUT, shell=True
|
|
||||||
)
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ class AutoNewWindowsUser(AutoNewUser):
|
||||||
|
|
||||||
windows_cmds = get_windows_commands_to_add_user(self.username, self.password, True)
|
windows_cmds = get_windows_commands_to_add_user(self.username, self.password, True)
|
||||||
logger.debug("Trying to add {} with commands {}".format(self.username, str(windows_cmds)))
|
logger.debug("Trying to add {} with commands {}".format(self.username, str(windows_cmds)))
|
||||||
_ = subprocess.check_output(windows_cmds, stderr=subprocess.STDOUT, shell=True)
|
_ = subprocess.check_output(windows_cmds, stderr=subprocess.STDOUT)
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
# Importing these only on windows, as they won't exist on linux.
|
# Importing these only on windows, as they won't exist on linux.
|
||||||
|
@ -127,9 +127,7 @@ class AutoNewWindowsUser(AutoNewUser):
|
||||||
self.username, str(commands_to_deactivate_user)
|
self.username, str(commands_to_deactivate_user)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
_ = subprocess.check_output(
|
_ = subprocess.check_output(commands_to_deactivate_user, stderr=subprocess.STDOUT)
|
||||||
commands_to_deactivate_user, stderr=subprocess.STDOUT, shell=True
|
|
||||||
)
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
raise NewUserError("Can't deactivate user {}. Info: {}".format(self.username, err))
|
raise NewUserError("Can't deactivate user {}. Info: {}".format(self.username, err))
|
||||||
|
|
||||||
|
@ -141,8 +139,6 @@ class AutoNewWindowsUser(AutoNewUser):
|
||||||
self.username, str(commands_to_delete_user)
|
self.username, str(commands_to_delete_user)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
_ = subprocess.check_output(
|
_ = subprocess.check_output(commands_to_delete_user, stderr=subprocess.STDOUT)
|
||||||
commands_to_delete_user, stderr=subprocess.STDOUT, shell=True
|
|
||||||
)
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
raise NewUserError("Can't delete user {}. Info: {}".format(self.username, err))
|
raise NewUserError("Can't delete user {}. Info: {}".format(self.username, err))
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import logging
|
import logging
|
||||||
|
import shlex
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
@ -45,14 +46,20 @@ class WindowsUpgrader(object):
|
||||||
opts.parent, opts.tunnel, opts.server, opts.depth
|
opts.parent, opts.tunnel, opts.server, opts.depth
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# TODO: Replace all of this string templating with a function that accepts
|
||||||
|
# the necessary parameters and returns a list of arguments.
|
||||||
monkey_cmdline = (
|
monkey_cmdline = (
|
||||||
MONKEY_CMDLINE_WINDOWS % {"monkey_path": WormConfiguration.dropper_target_path_win_64}
|
MONKEY_CMDLINE_WINDOWS % {"monkey_path": WormConfiguration.dropper_target_path_win_64}
|
||||||
+ monkey_options
|
+ monkey_options
|
||||||
)
|
)
|
||||||
|
|
||||||
monkey_process = subprocess.Popen(
|
monkey_cmdline_split = shlex.split(
|
||||||
monkey_cmdline,
|
monkey_cmdline,
|
||||||
shell=True,
|
posix=False, # won't try resolving "\" in paths as part of escape sequences
|
||||||
|
)
|
||||||
|
|
||||||
|
monkey_process = subprocess.Popen(
|
||||||
|
monkey_cmdline_split,
|
||||||
stdin=None,
|
stdin=None,
|
||||||
stdout=None,
|
stdout=None,
|
||||||
stderr=None,
|
stderr=None,
|
||||||
|
|
|
@ -36,6 +36,7 @@ mongomock = "==3.19.0"
|
||||||
pytest = ">=5.4"
|
pytest = ">=5.4"
|
||||||
requests-mock = "==1.8.0"
|
requests-mock = "==1.8.0"
|
||||||
black = "==20.8b1"
|
black = "==20.8b1"
|
||||||
|
dlint = "==0.11.0"
|
||||||
flake8 = "==3.9.0"
|
flake8 = "==3.9.0"
|
||||||
pytest-cov = "*"
|
pytest-cov = "*"
|
||||||
isort = "==5.8.0"
|
isort = "==5.8.0"
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"_meta": {
|
"_meta": {
|
||||||
"hash": {
|
"hash": {
|
||||||
"sha256": "9d575bcb35dba0389e8a68dd285f9ed7015fbcc4a42cffff5301777497337616"
|
"sha256": "4fdfe90af14139cf855a0363ad0acbe7fb307b35b038e2c099c4d1227322a13b"
|
||||||
},
|
},
|
||||||
"pipfile-spec": 6,
|
"pipfile-spec": 6,
|
||||||
"requires": {
|
"requires": {
|
||||||
|
@ -171,7 +171,7 @@
|
||||||
"sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff",
|
"sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff",
|
||||||
"sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"
|
"sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"
|
||||||
],
|
],
|
||||||
"markers": "python_version != '3.4' and sys_platform == 'win32'",
|
"markers": "python_version != '3.4'",
|
||||||
"version": "==0.4.3"
|
"version": "==0.4.3"
|
||||||
},
|
},
|
||||||
"coloredlogs": {
|
"coloredlogs": {
|
||||||
|
@ -1076,7 +1076,7 @@
|
||||||
"sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff",
|
"sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff",
|
||||||
"sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"
|
"sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"
|
||||||
],
|
],
|
||||||
"markers": "python_version != '3.4' and sys_platform == 'win32'",
|
"markers": "python_version != '3.4'",
|
||||||
"version": "==0.4.3"
|
"version": "==0.4.3"
|
||||||
},
|
},
|
||||||
"coverage": {
|
"coverage": {
|
||||||
|
@ -1144,6 +1144,13 @@
|
||||||
],
|
],
|
||||||
"version": "==0.3.1"
|
"version": "==0.3.1"
|
||||||
},
|
},
|
||||||
|
"dlint": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:e7297325f57e6b5318d88fba2497f9fea6830458cd5aecb36150856db010f409"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==0.11.0"
|
||||||
|
},
|
||||||
"filelock": {
|
"filelock": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59",
|
"sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59",
|
||||||
|
|
|
@ -33,9 +33,9 @@ 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(
|
r = requests.post( # noqa: DUO123
|
||||||
url=island_server_path, data=post_data, verify=False, timeout=SHORT_REQUEST_TIMEOUT
|
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:
|
||||||
|
|
|
@ -9,7 +9,7 @@ TEST_USER = "test_user"
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def subprocess_check_output_spy(monkeypatch):
|
def subprocess_check_output_spy(monkeypatch):
|
||||||
def mock_check_output(command, stderr, shell):
|
def mock_check_output(command, stderr):
|
||||||
mock_check_output.command = command
|
mock_check_output.command = command
|
||||||
|
|
||||||
mock_check_output.command = ""
|
mock_check_output.command = ""
|
||||||
|
@ -21,11 +21,11 @@ def subprocess_check_output_spy(monkeypatch):
|
||||||
|
|
||||||
def test_new_user_expires(subprocess_check_output_spy):
|
def test_new_user_expires(subprocess_check_output_spy):
|
||||||
with (AutoNewLinuxUser(TEST_USER, "password")):
|
with (AutoNewLinuxUser(TEST_USER, "password")):
|
||||||
assert "--expiredate" in subprocess_check_output_spy.command
|
assert "--expiredate" in " ".join(subprocess_check_output_spy.command)
|
||||||
assert "--inactive 0" in subprocess_check_output_spy.command
|
assert "--inactive 0" in " ".join(subprocess_check_output_spy.command)
|
||||||
|
|
||||||
|
|
||||||
def test_new_user_try_delete(subprocess_check_output_spy):
|
def test_new_user_try_delete(subprocess_check_output_spy):
|
||||||
with (AutoNewLinuxUser(TEST_USER, "password")):
|
with (AutoNewLinuxUser(TEST_USER, "password")):
|
||||||
pass
|
pass
|
||||||
assert f"deluser {TEST_USER}" in subprocess_check_output_spy.command
|
assert f"deluser {TEST_USER}" in " ".join(subprocess_check_output_spy.command)
|
||||||
|
|
Loading…
Reference in New Issue