diff --git a/automated_detection_testing/ci/attack_range_testing/Dockerfile b/automated_detection_testing/ci/attack_range_testing/Dockerfile new file mode 100644 index 0000000000..7eb9d5c7f1 --- /dev/null +++ b/automated_detection_testing/ci/attack_range_testing/Dockerfile @@ -0,0 +1,20 @@ +FROM ubuntu:18.04 + +RUN apt-get update +RUN DEBIAN_FRONTEND="noninteractive" apt-get -y install tzdata +RUN apt-get install -y python3-dev git python-dev unzip python3-pip awscli +RUN apt-get install -y python-gitdb +RUN apt-get install -y wget unzip + +RUN wget --quiet https://releases.hashicorp.com/terraform/0.13.1/terraform_0.13.1_linux_amd64.zip \ + && unzip terraform_0.13.1_linux_amd64.zip \ + && mv terraform /usr/bin \ + && rm terraform_0.13.1_linux_amd64.zip + +ADD . /app + +WORKDIR /app +RUN pip3 install -r requirements.txt + +ENTRYPOINT ["python3", "honeypot_service.py"] +CMD ["-a", "build", "-r", "eu-west-2", "-n", "songoku"] \ No newline at end of file diff --git a/automated_detection_testing/ci/attack_range_testing/helpers/attack_range_controller.py b/automated_detection_testing/ci/attack_range_testing/helpers/attack_range_controller.py new file mode 100644 index 0000000000..828c05ac2e --- /dev/null +++ b/automated_detection_testing/ci/attack_range_testing/helpers/attack_range_controller.py @@ -0,0 +1,95 @@ +from shutil import which +import secrets +import string +import os +import logging +import sys +import time + +from helpers import aws_service + + +# Logger +logging.basicConfig(level=os.environ.get("LOGLEVEL", "INFO")) +LOGGER = logging.getLogger(__name__) + + +def create_random_password(): + alphabet = string.ascii_letters + string.digits + password = ''.join(secrets.choice(alphabet) for i in range(10)) + password = '!1' + password + 'n:' + return password + + +def configure_attack_range_honeypot(region, honeypot_name, password): + sys.path.append(os.path.join(os.getcwd(),'attack_range_honeypot')) + + with open('attack_range_honeypot/terraform/aws/resources.tf', 'r') as file : + filedata = file.read() + + filedata = filedata.replace('[region]', region) + filedata = filedata.replace('[name]', honeypot_name) + + with open('attack_range_honeypot/terraform/aws/resources.tf', 'w+') as file: + file.write(filedata) + + + with open('attack_range_honeypot/attack_range.conf.template', 'r') as file : + filedata = file.read() + + filedata = filedata.replace('attack_range_password = asda:?wlflas1234qw?', 'attack_range_password = ' + password) + filedata = filedata.replace('windows_server = 0', 'windows_server = 1') + filedata = filedata.replace('region = eu-central-1', 'region = ' + region) + filedata = filedata.replace('range_name = default', 'range_name = ' + honeypot_name) + + with open('attack_range_honeypot/attack_range.conf', 'w') as file: + file.write(filedata) + + # check if terraform is installed + if which('terraform') is None: + sys.exit(1) + else: + # init terraform + os.system('cd attack_range_honeypot/terraform/aws && terraform init && cd ../../..') + + +def build_attack_range_honeypot(region, honeypot_name): + + password = create_random_password() + + configure_attack_range_honeypot(region, honeypot_name, password) + + module = __import__('attack_range') + module.sys.argv = ['attack_range', '--config', 'attack_range_honeypot/attack_range.conf', 'build'] + + try: + LOGGER.info(f"Build Attack Range Honeypot") + results = module.main(module.sys.argv) + except Exception as e: + LOGGER.error('Build Error: ' + str(e)) + module.sys.argv = ['attack_range', '--config', 'attack_range_honeypot/attack_range.conf', 'destroy'] + module.main(module.sys.argv) + sys.exit(1) + + return password + + +def destroy_attack_range_honeypot(data): + + region = data['region'] + honeypot_name = data['name'] + password = data['password'] + + configure_attack_range_honeypot(region, honeypot_name, password) + + module = __import__('attack_range') + module.sys.argv = ['attack_range', '--config', 'attack_range_honeypot/attack_range.conf', 'destroy'] + + try: + LOGGER.info(f"Destroy Attack Range Honeypot") + results = module.main(module.sys.argv) + except Exception as e: + LOGGER.error('Build Error: ' + str(e)) + module.sys.argv = ['attack_range', '--config', 'attack_range_honeypot/attack_range.conf', 'destroy'] + module.main(module.sys.argv) + sys.exit(1) diff --git a/automated_detection_testing/ci/attack_range_testing/helpers/aws_service.py b/automated_detection_testing/ci/attack_range_testing/helpers/aws_service.py new file mode 100644 index 0000000000..81d53ae314 --- /dev/null +++ b/automated_detection_testing/ci/attack_range_testing/helpers/aws_service.py @@ -0,0 +1,64 @@ +import boto3 +from botocore.config import Config +import time +import os +import json + + + +def create_tf_state_store(honeypot_name, region): + my_config = Config(region_name = region) + s3 = boto3.client('s3', config=my_config) + response = s3.create_bucket(Bucket=str('attack-range-detection-testing-bucket-' + honeypot_name), CreateBucketConfiguration={'LocationConstraint': region}) + + client = boto3.client('dynamodb', config=my_config) + response = client.create_table( + TableName=str('attack-range-detection-testing-state-' + honeypot_name), + KeySchema=[ + { + 'AttributeName': 'LockID', + 'KeyType': 'HASH' # Partition key + } + ], + AttributeDefinitions=[ + { + 'AttributeName': 'LockID', + 'AttributeType': 'S' + } + ], + ProvisionedThroughput={ + 'ReadCapacityUnits': 10, + 'WriteCapacityUnits': 10 + } + ) + + +def delete_tf_state_store(region, honeypot_name): + s3 = boto3.resource('s3', region_name=region) + bucket = s3.Bucket(str('attack-range-detection-testing-bucket-' + honeypot_name)) + bucket.objects.all().delete() + bucket.delete() + + dynamodb = boto3.resource('dynamodb', region_name=region) + table = dynamodb.Table(str('attack-range-detection-testing-state-' + honeypot_name)) + table.delete() + + +def get_secret(secret_name): + region_name = "eu-central-1" + session = boto3.session.Session() + client = session.client( + service_name='secretsmanager', + region_name=region_name + ) + + get_secret_value_response = client.get_secret_value(SecretId=secret_name) + + if 'SecretString' in get_secret_value_response: + secret = get_secret_value_response['SecretString'] + secret_obj = json.loads(secret) + + return secret_obj[secret_name] + + + \ No newline at end of file diff --git a/automated_detection_testing/ci/attack_range_testing/helpers/github_service.py b/automated_detection_testing/ci/attack_range_testing/helpers/github_service.py new file mode 100644 index 0000000000..5f23965bc8 --- /dev/null +++ b/automated_detection_testing/ci/attack_range_testing/helpers/github_service.py @@ -0,0 +1,16 @@ +import git +import os +import logging + +from helpers import aws_service + +# Logger +logging.basicConfig(level=os.environ.get("LOGLEVEL", "INFO")) +LOGGER = logging.getLogger(__name__) + + +def clone_honeypot_project(): + LOGGER.info(f"Clone Honeypot Project") + O_AUTH_TOKEN_GITHUB = aws_service.get_secret("github_token") + repo_obj = git.Repo.clone_from('https://' + O_AUTH_TOKEN_GITHUB + ':x-oauth-basic@github.com/splunk/attack_range_honeypot', "attack_range", branch='develop') + return repo_obj \ No newline at end of file diff --git a/automated_detection_testing/ci/attack_range_testing/honeypot_service.py b/automated_detection_testing/ci/attack_range_testing/honeypot_service.py new file mode 100644 index 0000000000..2a9e710bb5 --- /dev/null +++ b/automated_detection_testing/ci/attack_range_testing/honeypot_service.py @@ -0,0 +1,45 @@ +import os +from os import path +import sys +import argparse + +from helpers import github_service, aws_service, attack_range_controller + + +def main(args): + + parser = argparse.ArgumentParser(description="Attack Range Honeypot Service") + parser.add_argument("-a", "--action", required=True, + help="action") + parser.add_argument("-r", "--region", required=False, + help="aws region") + parser.add_argument("-n", "--name", required=True, + help="name of the honeypot") + + args = parser.parse_args() + region = args.region + name = args.name + action = args.action + + + if action == "build": + response = aws_service.get_entry_database(name) + if not response: + github_service.clone_honeypot_project() + #ssh_key_name, key_material = aws_service.create_key_pair(region) + aws_service.create_tf_state_store(name, region) + aws_service.create_entry_database(region, name, "building") + password = attack_range_controller.build_attack_range_honeypot(region, name) + aws_service.update_entry_database(name, password, "running") + + elif action == "destroy": + data = aws_service.get_entry_database(name) + if data: + github_service.clone_honeypot_project() + attack_range_controller.destroy_attack_range_honeypot(data) + aws_service.delete_entry_database(name) + aws_service.delete_tf_state_store(data['region'], name) + + +if __name__ == "__main__": + main(sys.argv[1:]) \ No newline at end of file diff --git a/automated_detection_testing/ci/attack_range_testing/requirements.txt b/automated_detection_testing/ci/attack_range_testing/requirements.txt new file mode 100644 index 0000000000..eacdfff0c8 --- /dev/null +++ b/automated_detection_testing/ci/attack_range_testing/requirements.txt @@ -0,0 +1,79 @@ +ansible==3.1.0 +ansible-runner==1.4.7 +apipkg==1.5 +aspy.yaml==1.3.0 +atomicwrites==1.4.0 +attackcti==0.3.4.3 +attrs==20.3.0 +azure-common==1.1.25 +azure-core==1.8.2 +azure-identity==1.4.1 +azure-mgmt-compute==17.0.0 +azure-mgmt-core==1.2.1 +azure-mgmt-network==16.0.0 +azure-mgmt-resource==15.0.0 +bcrypt==3.2.0 +boto3==1.17.30 +botocore==1.20.30 +certifi==2020.12.5 +cffi==1.14.5 +cfgv==2.0.1 +chardet==4.0.0 +configparser==5.0.2 +contextlib2==0.6.0.post1 +Deprecated==1.2.12 +dnspython==2.1.0 +docutils==0.16 +execnet==1.8.0 +gitdb==4.0.5 +GitPython==3.1.14 +identify==2.1.3 +idna==2.8 +importlib-metadata==3.7.3 +Jinja2==2.11.3 +jmespath==0.10.0 +lockfile==0.12.2 +MarkupSafe==1.1.1 +mock==4.0.3 +more-itertools==8.7.0 +mysql-connector-python==8.0.23 +nodeenv==1.3.4 +ntlm-auth==1.5.0 +packaging==20.9 +path==15.1.2 +path.py==12.5.0 +pexpect==4.8.0 +pluggy==0.13.1 +pre-commit==2.11.1 +protobuf==3.15.6 +psutil==5.8.0 +ptyprocess==0.7.0 +py==1.10.0 +pycparser==2.20 +PyGithub==1.54.1 +PyInquirer==1.0.3 +PyJWT<2.0.1 +PyNaCl==1.4.0 +pyparsing==2.4.7 +pytest==6.2.2 +python-daemon==2.3.0 +python-dateutil==2.8.1 +python-terraform==0.10.1 +pywinrm==0.4.1 +PyYAML==5.4.1 +requests==2.25.1 +requests-ntlm==1.1.0 +s3transfer==0.3.4 +six==1.13.0 +smmap==3.0.5 +splunk-sdk==1.6.15 +tabulate==0.8.9 +termcolor==1.1.0 +toml==0.10.2 +urllib3==1.26.4 +virtualenv==20.4.3 +wcwidth==0.2.5 +wget==3.2 +wrapt==1.12.1 +xmltodict==0.12.0 +zipp==3.4.1