File size: 7,320 Bytes
7c89ed7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
# Copyright (c) 2017 Mozilla Corporation

import json
from mozdef_util.utilities.key_exists import key_exists


class message(object):
    def __init__(self):
        '''
            Plugin used to fix object type discretions with cloudtrail messages
        '''
        self.registration = ['cloudtrail']
        self.priority = 10

        # Just add new entry to this dict to
        # automatically convert key mappings
        # which are mixed string and dict
        # into a dict with a raw_value key as the string value
        self.modify_keys = [
            'details.additionaleventdata',
            'details.apiversion',
            'details.serviceeventdetails',
            'details.requestparameters.attribute',
            'details.requestparameters.authparameters',
            'details.requestparameters.bucketpolicy.statement.principal.service',
            'details.requestparameters.bucketpolicy.statement.principal.aws',
            'details.requestparameters.callerreference',
            'details.requestparameters.description',
            'details.requestparameters.describecapacityreservationsrequest',
            'details.requestparameters.describecoippoolsrequest',
            'details.requestparameters.describeegressonlyinternetgatewaysrequest',
            'details.requestparameters.describefastsnapshotrestoresrequest',
            'details.requestparameters.describeflowlogsrequest',
            'details.requestparameters.describeflowlogsrequest.filter.value',
            'details.requestparameters.describehostsrequest',
            'details.requestparameters.describeinstancetypeofferingsrequest',
            'details.requestparameters.describeinstancetypesrequest',
            'details.requestparameters.describeipv6poolsrequest',
            'details.requestparameters.describelaunchtemplatesrequest',
            'details.requestparameters.describenatgatewaysrequest',
            'details.requestparameters.describepublicipv4poolsrequest',
            'details.requestparameters.describescheduledinstancesrequest',
            'details.requestparameters.describespotfleetrequestsrequest',
            'details.requestparameters.describevpcendpointconnectionnotificationsrequest',
            'details.requestparameters.describevpcendpointsrequest',
            'details.requestparameters.describevpcendpointsrequest.filter',
            'details.requestparameters.describevpcendpointsrequest.filter.value',
            'details.requestparameters.describevpcendpointsrequest.vpcendpointid',
            'details.requestparameters.describevpcendpointserviceconfigurationsrequest',
            'details.requestparameters.describevpcendpointservicesrequest',
            'details.requestparameters.disableapitermination',
            'details.requestparameters.distributionconfig.callerreference',
            'details.requestparameters.domainname',
            'details.requestparameters.domainnames',
            'details.requestparameters.ebsoptimized',
            'details.requestparameters.filter',
            'details.requestparameters.groupdescription',
            'details.requestparameters.iaminstanceprofile',
            'details.requestparameters.invalidationbatch.callerreference',
            'details.requestparameters.imageid',
            'details.requestparameters.instancetype',
            'details.requestparameters.logging',
            'details.requestparameters.logstreamname',
            'details.requestparameters.metrics',
            'details.requestparameters.notification',
            'details.requestparameters.notificationconfiguration',
            'details.requestparameters.rule',
            'details.requestparameters.schema',
            'details.requestparameters.sort',
            'details.requestparameters.source',
            'details.requestparameters.tagging',
            'details.requestparameters.vpc',
            'details.responseelements.availabilityzones',
            'details.responseelements.createddate',
            'details.responseelements.creationdate',
            'details.responseelements.creationtime',
            'details.responseelements.credentials',
            'details.responseelements.dbsubnetgroup',
            'details.responseelements.distribution.distributionconfig.callerreference',
            'details.responseelements.endpoint',
            'details.responseelements.findings.service.additionalinfo.unusual',
            'details.responseelements.invalidation.invalidationbatch.callerreference',
            'details.responseelements.lastmodified',
            'details.responseelements.lastmodifieddate',
            'details.responseelements.policy',
            'details.responseelements.responseparameters.method.response.header.access-control-allow-headers',
            'details.responseelements.responseparameters.method.response.header.access-control-allow-methods',
            'details.responseelements.responseparameters.method.response.header.access-control-allow-origin',
            'details.responseelements.role',
            'details.responseelements.securitygroups',
            'details.responseelements.state',
            'details.responseelements.subnets',
        ]

    def convert_key_raw_str(self, needle, haystack):
        num_levels = needle.split(".")
        if len(num_levels) == 0:
            return False
        current_pointer = haystack
        for updated_key in num_levels:
            if updated_key == num_levels[-1]:
                current_pointer[updated_key] = {
                    'raw_value': json.dumps(current_pointer[updated_key])
                }
                return haystack
            if updated_key in current_pointer:
                current_pointer = current_pointer[updated_key]
            else:
                return haystack

    def onMessage(self, message, metadata):
        '''
        Check if source is in the message, if not then add cloudtrail as the source.
        '''
        if 'source' not in message:
            return (message, metadata)

        if not message['source'] == 'cloudtrail':
            return (message, metadata)

        '''
        Check if details.requestparameters.htmlpart exists, if it does it's generally longer than 32000 bytes,
        so we'll truncate it to 4096 characters using the constant ES_FIELD_VALUE_LIMIT so that ES will ingest it,
        leaving us with knowledge of what the field contains without the overkill of storing the entire page.
        '''

        ES_FIELD_VALUE_LIMIT = 4095

        if 'requestparameters' in message['details'] and message['details']['requestparameters']:
            if 'htmlpart' in message['details']['requestparameters'] and message['details']['requestparameters']['htmlpart']:
                message['details']['requestparameters']['htmlpart'] = message['details']['requestparameters']['htmlpart'][0:ES_FIELD_VALUE_LIMIT]

        for modified_key in self.modify_keys:
            if key_exists(modified_key, message):
                message = self.convert_key_raw_str(modified_key, message)

        return (message, metadata)