def snapshot_volumes(self, volume_ids, region): if not isinstance(volume_ids, list): volume_ids = [volume_ids] client = connection.Connection(type='client', service='ec2', region=region).connect() session = self.get_aws_session(region=region) ec2 = session.resource('ec2') responses = [] for volume_id in volume_ids: description = 'Snapshot of {vid} for case {cn}'.format( vid=volume_id, cn=self.case_number) snapshot_response = client.create_snapshot(VolumeId=volume_id, Description=description) snapshot_id = snapshot_response['SnapshotId'] self.event_to_logs( 'Took a snapshot of volume {vid} to snapshot {sid}'.format( vid=volume_id, sid=snapshot_id)) #add tag to snapshot snapshot = ec2.Snapshot(snapshot_id) snapshot.create_tags( Tags=[dict(Key='cr-case-number', Value=self.case_number)]) responses.append(snapshot_response) return responses
def create_security_group(self, region): client = connection.Connection(type='client', service='ec2', region=region).connect() response = client.create_vpc(CidrBlock='10.0.0.0/16') self.vpc_id = response['Vpc']['VpcId'] self.event_to_logs('Created new security vpc {0}'.format(self.vpc_id)) response = client.modify_vpc_attribute( VpcId=self.vpc_id, EnableDnsHostnames=dict(Value=True)) group_name = ('cloudresponse_workstation-{case_number}_sg').format( case_number=self.case_number) description = 'A security group for the cloudresponse workstation' response = client.create_security_group(GroupName=group_name, Description=description, VpcId=self.vpc_id) self.sg_id = response['GroupId'] self.event_to_logs('Created new security group {0}'.format(self.sg_id)) self.add_aws_isolation_sg_rule(self.sg_id, region, self.examiner_cidr_range, 22, 'tcp') response = client.create_subnet(VpcId=self.vpc_id, CidrBlock='10.0.1.0/24') self.subnet_id = response['Subnet']['SubnetId'] self.event_to_logs('Created new subnet with id {0}'.format( self.subnet_id)) response = client.modify_subnet_attribute( SubnetId=self.subnet_id, MapPublicIpOnLaunch=dict(Value=True)) return self.sg_id
def prep_iam_role(self, region): role_name = ( "cloudresponse_workstation-{case_number}-{region}").format( case_number=self.case_number, region=region) self.iam_client = connection.Connection(type='client', service='iam').connect() roles = self.get_roles() role_search = filter(lambda x: x['RoleName'] == role_name, roles) if len(role_search) == 1: self.event_to_logs('Found policy: {0}'.format(role_name)) self.instance_profile = role_name return role_name assume_policy_document = dict( Version="2012-10-17", Statement=[ dict(Sid='', Effect='Allow', Principal=dict(Service="ec2.amazonaws.com"), Action="sts:AssumeRole") ]) response = self.iam_client.create_role( RoleName=role_name, AssumeRolePolicyDocument=json.dumps(assume_policy_document)) self.event_to_logs('Created policy: {0}'.format(role_name)) policies = [ 'arn:aws:iam::aws:policy/AmazonEC2FullAccess', 'arn:aws:iam::aws:policy/IAMFullAccess', 'arn:aws:iam::aws:policy/AmazonS3FullAccess', 'arn:aws:iam::aws:policy/AWSCloudTrailReadOnlyAccess' ] for policy in policies: response = self.iam_client.attach_role_policy(RoleName=role_name, PolicyArn=policy) self.event_to_logs( 'Attaching policy {policy} to role {role}'.format( policy=policy, role=role_name)) response = self.iam_client.create_instance_profile( InstanceProfileName=role_name) self.event_to_logs( 'Created instance profile with name {0} and ID {1}'.format( role_name, response['InstanceProfile']['InstanceProfileId'])) # instance profile needs a few seconds before it is ready time.sleep(30) response = self.iam_client.add_role_to_instance_profile( InstanceProfileName=role_name, RoleName=role_name) self.event_to_logs( 'Attached role {0} to instance profile {0}'.format(role_name)) self.instance_profile = role_name # instance profile needs a few seconds before it is ready time.sleep(5) return role_name
def get_aws_instance_metadata(self, instance_id, region): client = connection.Connection(type='client', service='ec2', region=region).connect() metadata = client.describe_instances(Filters=[{ 'Name': 'instance-id', 'Values': [instance_id] }])['Reservations'] return metadata
def stop_instance(self, instance_id, region, force=False): client = connection.Connection(type='client', service='ec2', region=region).connect() response = client.stop_instances(InstanceIds=[instance_id], Force=force) self.event_to_logs( 'Stopping instance: instance_id={0}'.format(instance_id)) return response
def add_incident_tag_to_instance(self, instance_dict): region = instance_dict['region'] instance_id = instance_dict['instance_id'] client = connection.Connection(type='client', service='ec2', region=region).connect() session = self.get_aws_session(region=region) ec2 = session.resource('ec2') tag = [{'Key': 'cr-case-number', 'Value': self.case_number}] client.create_tags(Resources=[instance_id], Tags=tag)
def setup(self): """ Get all the required information before doing the mitigation. """ client = connection.Connection(type='client', service='ec2').connect() self.event_to_logs("Initial connection to AmazonWebServices made.") self.amazon = aws.AmazonWebServices( connection.Connection(type='client', service='ec2')) self.available_regions = self.amazon.regions self.event_to_logs( "Inventory AWS Regions Complete {region_count} found.".format( region_count=len(self.amazon.regions))) self.availability_zones = self.amazon.availability_zones self.event_to_logs( "Inventory Availability Zones Complete {zone_count} found.".format( zone_count=len(self.amazon.availability_zones))) self.event_to_logs( "Beginning inventory of instances world wide. This might take a minute..." ) self.aws_inventory = inventory.Inventory( connection.Connection(type='client', service='ec2'), self.available_regions) self.event_to_logs( "Inventory complete. Proceeding to resource identification.") self.inventory = self.aws_inventory.inventory self.recent_instances = self.aws_inventory.recent() self.log_aws_recent_instances(self.recent_instances) self.trail_logs = cloudtrail.CloudTrail( regions=self.amazon.regions, client=connection.Connection(type='client', service='cloudtrail')).trail_list
def log_aws_instance_screenshot(self, instance_id, region): client = connection.Connection(type='client', service='ec2', region=region).connect() response = client.get_console_screenshot(InstanceId=instance_id, WakeUp=True) logfile = ("/tmp/{case_number}-{instance_id}-screenshot.jpg").format( case_number=self.case_number, instance_id=instance_id) fh = open(logfile, "wb") fh.write(base64.b64decode(response['ImageData'])) fh.close()
def create(self): AMI_ID = settings.AMI_IDS[self.region] # 1. Generate SSH Key pair (if key not specified) key_name = self.prep_key(region=self.region) # 2. Create / Find IAM Role role_name = self.prep_iam_role(region=self.region) # 3. Create security group security_group_id = self.create_security_group(region=self.region) # 4. Create and attach internet gateway internet_gateway_id = self.create_internet_gateway(region=self.region) # 5. Launch instance into user's account with IAM Role and pub key self.instance_id = self.launch_ami(self.region, AMI_ID, key_name, role_name, security_group_id) # 6. Tag instance with case reference number client = connection.Connection(type='client', service='ec2', region=self.region).connect() tag = [ { 'Key': 'cr-case-number', 'Value': self.case_number }, { 'Key': 'cr-workstation', 'Value': 'true' }, ] client.create_tags(Resources=[self.instance_id], Tags=tag) # 7. Provide user with login info. ip_address = self.get_public_ip(self.region) command = self.format_ssh_command(ip_address) self.event_to_logs( 'connect to the workstation instance with: {0}'.format(command)) print( 'connect to the workstation instance with: \n {0}'.format(command))
def create_internet_gateway(self, region, timeout_seconds=300): ''' This code isn't needed, but I just finished writing it and don't have the heart to delete it yet ''' client = connection.Connection(type='client', service='ec2', region=region).connect() response = client.create_internet_gateway() internet_gateway_id = response['InternetGateway']['InternetGatewayId'] self.event_to_logs( 'Created InternetGateway with ID {0}'.format(internet_gateway_id)) response = client.attach_internet_gateway( InternetGatewayId=internet_gateway_id, VpcId=self.vpc_id) self.event_to_logs('Attaching InternetGateway {0} to VPC {1}'.format( internet_gateway_id, self.vpc_id)) attached = False for i in range(timeout_seconds): self.event_to_logs( 'Checking if InternetGateway {0} is attached to VPC {1}'. format(internet_gateway_id, self.vpc_id)) response = client.describe_internet_gateways( InternetGatewayIds=[internet_gateway_id]) if is_internet_gateway_attached(response, internet_gateway_id, self.vpc_id): attached = True break time.sleep(1) if not attached: raise RuntimeError('Could not attach IG to VPC') self.internet_gateway_id = internet_gateway_id ec2 = boto3.resource('ec2') vpc = ec2.Vpc(self.vpc_id) response = client.describe_route_tables( Filters=[dict(Name='vpc-id', Values=[self.vpc_id])]) route_table_id = response['RouteTables'][0]['RouteTableId'] client.create_route(RouteTableId=route_table_id, DestinationCidrBlock='0.0.0.0/0', GatewayId=internet_gateway_id) return self.internet_gateway_id
def get_public_ip(self, region, timeout_seconds=300): client = connection.Connection(type='client', service='ec2', region=region).connect() instance = None for i in range(timeout_seconds): self.event_to_logs('Checking if instance {0} is running.'.format( self.instance_id)) response = client.describe_instances( InstanceIds=[self.instance_id]) instance = running_instance_or_none(response, self.instance_id) if instance is not None: break time.sleep(1) if instance is None: raise RuntimeError('Timeout out waiting for instance to start') ip_address = instance['PublicIpAddress'] self.event_to_logs('Instance {0} is running at {1}'.format( self.instance_id, ip_address)) return ip_address
def prep_key(self, region): if self.key_name is not None: return self.key_name self.key_directory = tempfile.mkdtemp(prefix='ws_keys_') private_key_handle, self.private_key = tempfile.mkstemp( suffix='.pem', prefix=self.case_number) key_name = os.path.basename(self.private_key) client = connection.Connection(type='client', service='ec2', region=region).connect() response = client.create_key_pair(KeyName=key_name) os.write(private_key_handle, response['KeyMaterial']) os.close(private_key_handle) self.event_to_logs('Wrote new key to {0}'.format(self.private_key)) return key_name
def create_aws_isolation_sg(self, region, vpc_id, instance_id): client = connection.Connection(type='client', service='ec2', region=region).connect() session = self.get_aws_session(region=region) description = "Lanched by AWS IR for Case " + self.case_number sg_name = "isolation-sg-{case_number}-{instance}-{uuid}".format( case_number=self.case_number, instance=instance_id, uuid=str(uuid.uuid4())) sg = client.create_security_group(GroupName=sg_name, Description=description, VpcId=vpc_id) self.event_to_logs("Security Group Created " + sg['GroupId']) ec2 = session.resource('ec2') security_group_id = sg['GroupId'] isolate_sg = ec2.SecurityGroup(security_group_id) isolate_sg.revoke_egress( IpPermissions=isolate_sg.ip_permissions_egress) self.event_to_logs("Security Group Egress Access Revoked for " + sg['GroupId']) return sg['GroupId']
def launch_ami(self, region, ami_id, key_name, role_name, security_group_id): client = connection.Connection(type='client', service='ec2', region=region).connect() script = """#!/bin/bash echo CASE_NUMBER="$CASE_NUMBER" >> /opt/threatresponse/.env chmod -R 777 /opt/timesketch/contrib/*_data docker pull threatresponse/threatresponse:latest cd /opt/threatresponse && /usr/local/bin/docker-compose up -d cd /opt/timesketch && /usr/local/bin/docker-compose up -d """ script = script.replace('$CASE_NUMBER', self.case_number) response = client.run_instances( ImageId=ami_id, MinCount=1, MaxCount=1, KeyName=key_name, SecurityGroupIds=[security_group_id], SubnetId=self.subnet_id, IamInstanceProfile=dict(Name=self.instance_profile), BlockDeviceMappings=[{ "DeviceName": "/dev/xvda", "Ebs": { "VolumeSize": 64 } }], InstanceType='m3.large', UserData=script) instance_id = response['Instances'][0]['InstanceId'] self.event_to_logs( 'Launching AMI {ami_id} to instace id {instance_id}'.format( ami_id=ami_id, instance_id=instance_id)) return instance_id
def get_aws_instance_console_output(self, instance_id, region): client = connection.Connection(type='client', service='ec2', region=region).connect() output = client.get_console_output(InstanceId=instance_id) return output