Skip to content

Commit

Permalink
Merge pull request #32 from leboncoin/4.4.3
Browse files Browse the repository at this point in the history
4.4.3
  • Loading branch information
Nicolas Béguier authored Mar 10, 2023
2 parents 2a11619 + 41fbf58 commit 1269d48
Show file tree
Hide file tree
Showing 8 changed files with 87 additions and 17 deletions.
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,20 @@ CHANGELOG
AWS-TOWER
-----

4.4.3
-----

2023/03/10

### New feature
- Display EC2 OS info and improve filter
- Pattern: add rule has_attribute_contain*
- Add --only-dangerous-actions for iam verb

### Fixtures
- Fix `--layer` and add Usage in README


4.4.2
-----

Expand Down
20 changes: 19 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ options:
```bash
$ aws-tower iam --help
usage: aws_tower_cli.py iam [-h] [-s SOURCE] [-a ACTION] [--min-rights {admin,poweruser,reader}] [--service SERVICE] [-d] [-v] profile
usage: aws_tower_cli.py iam [-h] [-s SOURCE] [-a ACTION] [--min-rights {admin,poweruser,reader}] [--service SERVICE] [-d] [--only-dangerous-actions] [-v] profile
positional arguments:
profile A valid profile name configured in the ~/.aws/config file
Expand All @@ -131,6 +131,8 @@ options:
Minimum actions rights
--service SERVICE Action Category to match
-d, --display Display informations about the source ARN
--only-dangerous-actions
Display IAM dangerous actions only
-v, --verbose Verbose output of the account assets
```
Expand All @@ -150,6 +152,22 @@ $ export PATROWL_PUBLIC_ENDPOINT=http://localhost/
$ python -c 'from monitoring.aws_lambda import aws_tower_child; aws_tower_child.main({ "my-account-profile": "arn:aws:iam::xxxxxxxxxxxxx:role/readonly", "env": "pro|pre|dev", "region_name": "eu-west-1", "meta_types": ["S3"] })'
```
## Usage (layers)
```bash
$ aws-tower --layer > /tmp/aws-tower-layer.json
```
Then, go to [Attack Navigator](https://mitre-attack.github.io/attack-navigator/#comment_underline=false)
Click on "Open Existing Layer" -> "Upload from local"
Upload your generated file, `/tmp/aws-tower-layer.json`
You will have a warning, **Click No** to refuse the upgrade on Att&ck v12, stay in v11.
## Findings
Some rules already exists in `config/rules.yaml.sample`, but you can add your own too.
Expand Down
8 changes: 7 additions & 1 deletion aws_tower_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
# from pdb import set_trace as st

CONSOLE = console.Console()
VERSION = '4.4.2'
VERSION = '4.4.3'

def audit_handler(session, args, meta_types, cache):
"""
Expand Down Expand Up @@ -150,6 +150,7 @@ def iam_handler(session, args, cache, csl):
csl,
iam_action_passlist=variables.IAM_ACTION_PASSLIST,
iam_rolename_passlist=variables.IAM_ROLENAME_PASSLIST,
only_dangerous_actions=args.only_dangerous_actions,
verbose=args.verbose)
elif args.source and args.action:
account_id = session.client('sts').get_caller_identity().get('Account')
Expand All @@ -170,6 +171,7 @@ def iam_handler(session, args, cache, csl):
csl,
iam_action_passlist=variables.IAM_ACTION_PASSLIST,
iam_rolename_passlist=variables.IAM_ROLENAME_PASSLIST,
only_dangerous_actions=args.only_dangerous_actions,
verbose=args.verbose)

def main(verb, args):
Expand Down Expand Up @@ -395,6 +397,10 @@ def main(verb, args):
'-d', '--display',
action='store_true',
help='Display informations about the source ARN')
IAM_PARSER.add_argument(
'--only-dangerous-actions',
action='store_true',
help='Display IAM dangerous actions only')
IAM_PARSER.add_argument(
'-v', '--verbose',
action='store_true',
Expand Down
2 changes: 1 addition & 1 deletion config/rules.yaml.sample
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
version: 4.4.2
version: 4.4.0
types:
security_group:
description: Check each rule on each security group and on each source
Expand Down
7 changes: 6 additions & 1 deletion libs/asset_type_ec2.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class EC2(AssetType):
def __init__(self, name: str, private_ip: str, public: bool=False):
super().__init__('EC2', name, public=public)
self.operating_system = 'unknown'
self.operating_system_name = 'unknown'
self.private_ip = private_ip
self.public_ip = ''
self.security_groups = {}
Expand All @@ -45,7 +46,7 @@ def report(self, report, brief=False):
asset_report = self.report_brief()
else:
asset_report = {
'OS': self.operating_system,
'OS': f'{self.operating_system} ({self.operating_system_name})',
'PrivateIP': self.private_ip,
'InstanceID': self.instance_id
}
Expand Down Expand Up @@ -212,6 +213,10 @@ def scan(ec2, sg_raw, subnets_raw, kp_raw, boto_session, public_only):
ec2_asset.operating_system = ec2_res.Image(ec2['ImageId']).platform_details
except:
pass
try:
ec2_asset.operating_system_name = ec2_res.Image(ec2['ImageId']).name
except:
pass
if 'Tags' in ec2:
ec2_asset.name = get_tag(ec2['Tags'], 'Name')
eks_cluster_name = [ i['Key'].split('/')[-1] for i in ec2['Tags'] if i['Key'].startswith('kubernetes.io/cluster/') ]
Expand Down
29 changes: 19 additions & 10 deletions libs/iam_scan.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ def iam_display(
console,
iam_action_passlist=[],
iam_rolename_passlist=[],
only_dangerous_actions=False,
verbose=False):
"""
Display information about the ARN
Expand Down Expand Up @@ -234,11 +235,14 @@ def iam_display(
# Display actions
iam_obj.actions = actions
iam_obj.simplify_actions()
if iam_obj.admin_actions:
console.print(f'[red]Admin actions: {iam_obj.admin_actions}[/red]')
if iam_obj.poweruser_actions and min_rights != 'admin':
console.print(f'[yellow]Poweruser actions: {iam_obj.poweruser_actions}[/yellow]')
console.print(f'ALL Actions: {set(actions)}')
if iam_obj.dangerous_actions:
console.print(f'[red]Dangerous actions: {iam_obj.dangerous_actions}[/red]')
if not only_dangerous_actions:
if iam_obj.admin_actions:
console.print(f'[red]Admin actions: {iam_obj.admin_actions}[/red]')
if iam_obj.poweruser_actions and min_rights != 'admin':
console.print(f'[yellow]Poweruser actions: {iam_obj.poweruser_actions}[/yellow]')
console.print(f'ALL Actions: {set(actions)}')

def get_role_services(role):
"""
Expand Down Expand Up @@ -314,6 +318,7 @@ def iam_display_roles(
console,
iam_action_passlist=[],
iam_rolename_passlist=[],
only_dangerous_actions=False,
verbose=False):
"""
Display all roles actions
Expand All @@ -327,8 +332,12 @@ def iam_display_roles(
arn=arn,
service=service)
for role in roles:
actions = role.print_actions(min_rights)
if actions:
console.print(actions)
if verbose:
console.print(f'Actions: {role.actions}')
if only_dangerous_actions:
if role.dangerous_actions:
print(f'{role.name}: {role.dangerous_actions}')
else:
actions = role.print_actions(min_rights)
if actions:
console.print(actions)
if verbose:
console.print(f'Actions: {role.actions}')
17 changes: 17 additions & 0 deletions libs/patterns.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ class Patterns:
'data_sources': ['attribute_value'],
'conditions': ['attribute_value']
},
'has_attribute_contain': {
'data_sources': ['attribute_value'],
'conditions': ['attribute_value']
},
'is_cidr': {
'data_sources': ['source'],
'conditions': ['is_cidr']
Expand Down Expand Up @@ -318,6 +322,19 @@ def _check_rule_has_attribute_not_equal(self, data_sources, conditions):
"""
return not self._check_rule_has_attribute_equal(data_sources, conditions)

def _check_rule_has_attribute_contain(self, data_sources, conditions):
"""Check if data_sources['attribute_value'] has the attribute equal to conditions['attribute_value']
Check rule "has_attribute_contain"
:param data_sources: Where we want to find the conditions
:type data_sources: {"attribute_value": mixed}
:param conditions: Attribute value to be equal
:type conditions: {"attribute_value": mixed}
:return: True if one contain the other
:rtype: bool
"""
return data_sources['attribute_value'].lower() in conditions['attribute_value'].lower() or conditions['attribute_value'].lower() in data_sources['attribute_value'].lower()

def _check_rule_in(self, data_sources, conditions):
"""Check if conditions['data_element'] may be found in data_sources['data_list']
Check rule "in"
Expand Down
7 changes: 4 additions & 3 deletions libs/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,9 @@ def generate_layer(rules_path):
for rule in [
*rules['types']['security_group']['findings'],
*rules['types']['attributes']['findings']]:
if 'techniques' not in rule or i not in rule['techniques']:
if 'metadata' not in rule or i not in rule['metadata']:
continue
for tech_id in rule['techniques'][i]:
for tech_id in rule['metadata'][i]:
tech_ids.add(tech_id)
for tech_id in tech_ids:
# Check if technique is not already in the layer
Expand Down Expand Up @@ -400,7 +400,8 @@ def search_filter_in(asset, filter_str):
if asset.get_type() == 'RDS' and '==' in asset.engine:
is_found = asset.engine.split('==')[1].startswith(version)
elif filter_str.startswith('os:') and hasattr(asset, 'operating_system'):
is_found = asset.operating_system.lower().startswith(filter_str.split(':')[1])
os_name = f'{asset.operating_system}+{asset.operating_system_name}'.lower()
is_found = os_name in filter_str.split(':')[1] or filter_str.split(':')[1] in os_name
else:
if filter_str in asset.name.lower():
return True
Expand Down

0 comments on commit 1269d48

Please sign in to comment.