Skip to content

Commit

Permalink
Merge pull request #48 from swimlane/0_8_4_release
Browse files Browse the repository at this point in the history
0.8.4 Release
  • Loading branch information
MSAdministrator authored Apr 13, 2022
2 parents 4075e5d + 18087fd commit 7d9d308
Show file tree
Hide file tree
Showing 13 changed files with 99 additions and 37 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# CHANGELOG

## 0.8.4 - 2022-03-25

* Updated formatting of executor for AWS and local runners
* Updated documentation
* Added formatting constants to base class to improve updating of windows variables on command line runners

## 0.7.0 - 2022-01-04

* Updated argument handling in get_atomics Retrieving Atomic Tests with specified destination in /opt throws unexpected keyword argument error #28
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ pip3 install --upgrade pip
pip3 install setuptools_rust

# Back to our regularly scheduled programming . . .

pip install -r requirements.txt
python setup.py install
```

Expand All @@ -93,6 +93,7 @@ python setup.py install
```bash
git clone https://github.com/swimlane/atomic-operator.git
cd atomic-operator
pip install -r requirements.txt
python setup.py install
```

Expand Down
3 changes: 0 additions & 3 deletions atomic_operator/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1 @@
__version__ = "0.8.3"


from .atomic_operator import AtomicOperator
10 changes: 10 additions & 0 deletions atomic_operator/__meta__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
__title__ = 'atomic-operator'
__description__ = 'A python package to execute Atomic tests'
__url__ = 'https://github.com/swimlane/atomic-operator'
__version__ = '0.8.4'
__author__ = 'Swimlane'
__author_email__ = 'info@swimlane.com'
__maintainer__ = 'MSAdministrator'
__maintainer_email__ = 'rickardja@live.com'
__license__ = 'MIT'
__copyright__ = 'Copyright 2022 Swimlane'
10 changes: 8 additions & 2 deletions atomic_operator/atomic/loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,14 @@ def load_technique(self, path_to_dir) -> dict:
with open(self.get_abs_path(path_to_dir), 'r', encoding="utf-8") as f:
return yaml.safe_load(f.read())
except:
self.__logger.warning(f"Unable to load technique in '{path_to_dir}'")

try:
# windows does not like get_abs_path so casting to string
with open(str(path_to_dir), 'r', encoding="utf-8") as f:
return yaml.safe_load(f.read())
except OSError as oe:
self.__logger.warning(f"Unable to load technique in '{path_to_dir}': {oe}")

def load_techniques(self) -> dict:
"""The main entrypoint when loading techniques from disk.
Expand All @@ -74,6 +79,7 @@ def load_techniques(self) -> dict:
technique = self.__get_file_name(atomic_entry)
if not self.__techniques.get(technique):
loaded_technique = self.load_technique(str(atomic_entry))
loaded_technique.update({'path': os.path.dirname(str(atomic_entry))})
self.__techniques[technique] = Atomic(**loaded_technique)
if loaded_technique:
loaded_technique.update({'path': os.path.dirname(str(atomic_entry))})
self.__techniques[technique] = Atomic(**loaded_technique)
return self.__techniques
19 changes: 18 additions & 1 deletion atomic_operator/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ class Base(metaclass=LoggingBase):
'macos': '/bin/bash'
}
}
VARIABLE_REPLACEMENTS = {
'command_prompt': {
'%temp%': "$env:TEMP"
}
}
_replacement_strings = [
'#{{{0}}}',
'${{{0}}}'
Expand Down Expand Up @@ -110,7 +115,7 @@ def _path_replacement(self, string, path):
pass
return string

def _replace_command_string(self, command: str, path:str, input_arguments: list=[]):
def _replace_command_string(self, command: str, path:str, input_arguments: list=[], executor=None):
if command:
command = self._path_replacement(command, path)
if input_arguments:
Expand All @@ -121,6 +126,12 @@ def _replace_command_string(self, command: str, path:str, input_arguments: list=
except:
# catching errors since some inputs are actually integers but defined as strings
pass
if executor and self.VARIABLE_REPLACEMENTS.get(executor):
for key,val in self.VARIABLE_REPLACEMENTS[executor].items():
try:
command = command.replace(key, val)
except:
pass
return self._path_replacement(command, path)

def _check_if_aws(self, test):
Expand All @@ -146,6 +157,12 @@ def _set_input_arguments(self, test, **kwargs):
if Base.CONFIG.prompt_for_input_args:
for input in test.input_arguments:
input.value = self.prompt_user_for_input(test.name, input)
for key,val in self.VARIABLE_REPLACEMENTS.items():
if test.executor.name == key:
for k,v in val.items():
for input in test.input_arguments:
if k in input.default:
input.value = input.default.replace(k,v)
for input in test.input_arguments:
if input.value == None:
input.value = input.default
Expand Down
7 changes: 4 additions & 3 deletions atomic_operator/execution/awsrunner.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,13 @@ def execute_process(self, command, executor=None, host=None, cwd=None, elevation
if executor in ['powershell']:
command = f"Start-Process PowerShell -Verb RunAs; {command}"
elif executor in ['cmd', 'command_prompt']:
command = f'cmd.exe /c "{command}"'
command = f'{self.command_map.get(executor).get(self.__local_system_platform)} /c "{command}"'
elif executor in ['sh', 'bash', 'ssh']:
command = f"sudo {command}"
else:
self.__logger.warning(f"Elevation is required but the executor '{executor}' is unknown!")
command = self._replace_command_string(command, self.CONFIG.atomics_path, input_arguments=self.test.input_arguments)
command = self._replace_command_string(command, self.CONFIG.atomics_path, input_arguments=self.test.input_arguments, executor=executor)
executor = self.command_map.get(executor).get(self.__local_system_platform)
p = subprocess.Popen(
executor,
shell=False,
Expand Down Expand Up @@ -89,5 +90,5 @@ def _get_executor_command(self):
def start(self):
response = self.__check_for_aws_cli()
if not response.get('error'):
return self.execute(executor=self._get_executor_command())
return self.execute(executor=self.test.executor.name)
return response
5 changes: 3 additions & 2 deletions atomic_operator/execution/localrunner.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ def execute_process(self, command, executor=None, host=None, cwd=None, elevation
command = f"sudo {command}"
else:
self.__logger.warning(f"Elevation is required but the executor '{executor}' is unknown!")
command = self._replace_command_string(command, self.CONFIG.atomics_path, input_arguments=self.test.input_arguments)
command = self._replace_command_string(command, self.CONFIG.atomics_path, input_arguments=self.test.input_arguments, executor=executor)
executor = self.command_map.get(executor).get(self.__local_system_platform)
p = subprocess.Popen(
executor,
shell=False,
Expand Down Expand Up @@ -81,4 +82,4 @@ def _get_executor_command(self):
return __executor

def start(self):
return self.execute(executor=self._get_executor_command())
return self.execute(executor=self.test.executor.name)
4 changes: 2 additions & 2 deletions atomic_operator/execution/statemachine.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ def __invoke_cmd(self, command, input_arguments=None, elevation_required=False):
self.__create_win_client(self.hostinfo)
# TODO: NEED TO ADD LOGIC TO TRANSFER FILES TO WINDOWS SYSTEMS USING CMD
Copier(windows_client=self.__win_client, elevation_required=elevation_required).copy(input_arguments)
command = self._replace_command_string(command, path='c:/temp', input_arguments=input_arguments)
command = self._replace_command_string(command, path='c:/temp', input_arguments=input_arguments, executor='command_prompt')
if elevation_required:
command = f'runas /user:{self.hostinfo.username}:{self.hostinfo.password} cmd.exe; {command}'
# TODO: NEED TO ADD LOGIC TO TRANSFER FILES TO WINDOWS SYSTEMS USING CMD
Expand All @@ -173,7 +173,7 @@ def __invoke_powershell(self, command, input_arguments=None, elevation_required=

# TODO: NEED TO ADD LOGIC TO TRANSFER FILES TO WINDOWS SYSTEMS USING POWERSHELL
Copier(windows_client=self.__win_client, elevation_required=elevation_required).copy(input_arguments=input_arguments)
command = self._replace_command_string(command, path='c:/temp', input_arguments=input_arguments)
command = self._replace_command_string(command, path='c:/temp', input_arguments=input_arguments, executor='powershell')
# TODO: NEED TO ADD LOGIC TO TRANSFER FILES TO WINDOWS SYSTEMS USING POWERSHELL
if elevation_required:
command = f'Start-Process PowerShell -Verb RunAs; {command}'
Expand Down
17 changes: 13 additions & 4 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# CHANGELOG

## 0.8.4 - 2022-03-25

* Updated formatting of executor for AWS and local runners
* Updated documentation
* Added formatting constants to base class to improve updating of windows variables on command line runners

## 0.7.0 - 2022-01-04

* Updated argument handling in get_atomics Retrieving Atomic Tests with specified destination in /opt throws unexpected keyword argument error #28
Expand All @@ -22,11 +28,14 @@
* Updating handling of passing --help to the run command
* Updated docs to reflect change

## 0.5.0 - 2021-11-19
## 0.5.0 - 2021-11-18

* Updated and expanded tests
* Added CI to build docs and deploy to pypi
* Updated localrunner to support windows based on changes made previously
* Updated handling of versioning
* Updated CI to handle versioning of docs and deployment on release
* Added better handling of extracting zip file
* Added safer loading of yaml files
* Update docs
* Improved logging across the board and implemented a debug switch

## 0.4.0 - 2021-11-15

Expand Down
3 changes: 2 additions & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ pip3 install --upgrade pip
pip3 install setuptools_rust

# Back to our regularly scheduled programming . . .

pip install -r requirements.txt
python setup.py install
```

Expand All @@ -88,6 +88,7 @@ python setup.py install
```bash
git clone https://github.com/swimlane/atomic-operator.git
cd atomic-operator
pip install -r requirements.txt
python setup.py install
```

Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ fire==0.4.0
requests==2.26.0
attrs==21.2.0
pypsrp==0.5.0
paramiko==2.7.2
paramiko>=2.10.1
pick==1.2.0
47 changes: 30 additions & 17 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,11 @@ def read(rel_path: str) -> str:
return fp.read()


def get_version(rel_path: str) -> str:
for line in read(rel_path).splitlines():
if line.startswith("__version__"):
# __version__ = "0.9"
delim = '"' if '"' in line else "'"
return line.split(delim)[1]
raise RuntimeError("Unable to find version string.")
here = os.path.abspath(os.path.dirname(__file__))

about = {}
with open(os.path.join(here, 'atomic_operator', '__meta__.py'), 'r', 'utf-8') as f:
exec(f.read(), about)


PROJECT_URLS = {
Expand Down Expand Up @@ -52,21 +50,36 @@ def get_version(rel_path: str) -> str:
]

setup(
name='atomic-operator',
version=get_version("atomic_operator/__init__.py"),
name=about['__title__'],
version=about['__version__'],
packages=find_packages(exclude=['tests*']),
license='MIT',
description='A python package to execute Atomic tests',
license=about['__license__'],
description=about['__description__'],
long_description=open('README.md').read(),
long_description_content_type="text/markdown",
project_urls=PROJECT_URLS,
install_requires=parse_requirements('./requirements.txt'),
install_requires=[
'requests>=2.20.0; python_version >= "3.6"',
'charset_normalizer~=2.0.0; python_version >= "3"',
'chardet>=3.0.2,<5; python_version < "3"',
'idna>=2.5,<3; python_version < "3"',
'idna>=2.5,<4; python_version >= "3"',
'urllib3>=1.21.1,<1.27',
'certifi>=2017.4.17',
'windows-curses>=2.2.0,<3.0.0; platform_system=="Windows" and python_version >= "3.6"',
'attrs>=21.3.0; python_version >= "3.6"',
'pyyaml>=6.0; python_version >= "3.6"',
'fire>=0.4.0; python_version >= "3.6"',
'pypsrp>=0.5.0; python_version >= "3.6"',
'paramiko>=2.7.2; python_version >= "3.6"',
'pick>=1.2.0; python_version >= "3.6"'
],
keywords=['atomic-red-team', 'att&ck', 'test', 'mitre', 'executor'],
url='https://github.com/swimlane/atomic-operator',
author='MSAdministrator',
author_email='rickardja@live.com',
maintainer='MSAdministrator',
maintainer_email='rickardja@live.com',
url=about['__url__'],
author=about['__author__'],
author_email=about['__author_email__'],
maintainer=about['__maintainer__'],
maintainer_email=about['__maintainer_email__'],
python_requires='>=3.6, <4',
classifiers=CLASSIFIERS,
package_data={
Expand Down

0 comments on commit 7d9d308

Please sign in to comment.