├── DerbyCon_8_-_Red_Team_Telemetry_Slides.pdf ├── cobaltstrike ├── event_spy.cna ├── filebeat │ ├── filebeat.yml │ ├── fields.yml │ └── teamserver.template.json ├── mitre_cs.py └── json_log.cna ├── empire ├── filebeat │ ├── filebeat.yml │ └── fields.yml ├── empire_enrich.py └── logstash │ └── empire.conf ├── packetbeat └── packetbeat.yml └── README.md /DerbyCon_8_-_Red_Team_Telemetry_Slides.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ztgrace/red_team_telemetry/HEAD/DerbyCon_8_-_Red_Team_Telemetry_Slides.pdf -------------------------------------------------------------------------------- /cobaltstrike/event_spy.cna: -------------------------------------------------------------------------------- 1 | # event spy script - https://www.cobaltstrike.com/aggressor-script/events.html 2 | on * { 3 | println("[ $+ $1 $+ ]: " . subarray(@_, 1)); 4 | } 5 | -------------------------------------------------------------------------------- /empire/filebeat/filebeat.yml: -------------------------------------------------------------------------------- 1 | filebeat.prospectors: 2 | - input_type: log 3 | paths: 4 | - "/opt/empire/empire.debug" 5 | - "/opt/Empire/empire.debug" 6 | 7 | output.logstash: 8 | hosts: ["logs.mycompany.com:5044"] 9 | ssl.certificate_authorities: ["/etc/ca.crt"] 10 | ssl.certificate: "/etc/client.crt" 11 | ssl.key: "/etc/client.key" 12 | 13 | setup.template: 14 | fields: fields.yml 15 | overwrite: true 16 | -------------------------------------------------------------------------------- /cobaltstrike/filebeat/filebeat.yml: -------------------------------------------------------------------------------- 1 | filebeat.prospectors: 2 | - input_type: log 3 | paths: ["/var/log/cobaltstrike/teamserver-*.json"] 4 | json.message_key: event 5 | json.keys_under_root: true 6 | json.add_error_key: true 7 | 8 | output.elasticsearch: 9 | hosts: ["127.0.0.1:9200"] 10 | template.fields: fields.yml 11 | index: "teamserver-%{[beat.version]}-%{+yyyy.MM.dd}" 12 | 13 | setup.template: 14 | name: "teamserver" 15 | pattern: "teamserver-*" 16 | setup.dashboards.index: "teamserver-*" 17 | fields: fields.yml 18 | path: teamserver.template.json 19 | overwrite: true 20 | -------------------------------------------------------------------------------- /empire/filebeat/fields.yml: -------------------------------------------------------------------------------- 1 | - key: empire 2 | type: group 3 | title: Empire Project 4 | description: > 5 | Contains event logs from the Empire Project Server 6 | fields: 7 | - name: agent 8 | type: keyword 9 | - name: empire.message 10 | type: text 11 | - name: empire.command 12 | type: keyword 13 | - name: empire.print 14 | type: text 15 | - name: empire.module 16 | type: keyword 17 | - name: implant.agent 18 | type: keyword 19 | - name: implant.extip 20 | type: keyword 21 | - name: implant.hostname 22 | type: keyword 23 | - name: implant.internalip 24 | type: ip 25 | - name: implant.lang_version 26 | type: text 27 | - name: implant.language 28 | type: keyword 29 | - name: implant.os 30 | type: text 31 | - name: implant.pid 32 | type: integer 33 | - name: implant.process 34 | type: text 35 | - name: implant.target 36 | type: keyword 37 | - name: implant.team 38 | type: keyword 39 | - name: implant.type 40 | name: keyword 41 | - name: implant.username 42 | type: keyword 43 | - name: listener 44 | type: keyword 45 | - name: listener_type 46 | type: keyword 47 | - name: json 48 | type: text 49 | - name: "@timestamp" 50 | type: date 51 | required: true 52 | format: date 53 | example: August 26th 2016, 12:35:53.332 54 | description: > 55 | The timestamp when the event log record was generated. 56 | -------------------------------------------------------------------------------- /packetbeat/packetbeat.yml: -------------------------------------------------------------------------------- 1 | packetbeat.interfaces.device: ens33 2 | packetbeat.flows: 3 | enabled: false 4 | timeout: 30s 5 | period: 10s 6 | packetbeat.protocols: 7 | - type: dns 8 | enabled: true 9 | ports: [53] 10 | include_authorities: true 11 | include_additionals: true 12 | send_request: true 13 | send_response: true 14 | transaction_timeout: 10s 15 | - type: http 16 | enabled: true 17 | ports: [80] 18 | send_headers: true 19 | send_all_headers: true 20 | include_body_for: ["text/plain", "text/xml", "audio/mp4"] 21 | send_request: true 22 | send_response: true 23 | - type: icmp 24 | enabled: false 25 | - type: amqp 26 | enabled: false 27 | ports: [5672] 28 | - type: cassandra 29 | enabled: false 30 | ports: [9042] 31 | - type: memcache 32 | enabled: false 33 | ports: [11211] 34 | - type: mysql 35 | enabled: false 36 | ports: [3306] 37 | - type: pgsql 38 | enabled: false 39 | ports: [5432] 40 | - type: redis 41 | enabled: false 42 | ports: [6379] 43 | - type: thrift 44 | enabled: false 45 | ports: [9090] 46 | - type: mongodb 47 | enabled: false 48 | ports: [27017] 49 | - type: nfs 50 | enabled: false 51 | ports: [2049] 52 | - type: tls 53 | enabled: true 54 | ports: [443] 55 | send_certificates: true 56 | output.elasticsearch: 57 | hosts: ["127.0.0.1:9200"] 58 | pipeline: geoip-info 59 | setup.template.settings: 60 | number_of_shards: 3 61 | codec: best_compression 62 | _source.enabled: true 63 | setup.kibana: 64 | host: "127.0.0.1:5601" 65 | logging.to_files: true 66 | logging.files: 67 | -------------------------------------------------------------------------------- /cobaltstrike/mitre_cs.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from stix2 import TAXIICollectionSource, Filter 4 | from taxii2client import Collection 5 | 6 | # Initialize dictionary to hold Enterprise ATT&CK content 7 | attack = {} 8 | 9 | # Establish TAXII2 Collection instance for Enterprise ATT&CK collection 10 | collection = Collection("https://cti-taxii.mitre.org/stix/collections/95ecc380-afe9-11e4-9b6c-751b66dd541e/") 11 | 12 | # Supply the collection to TAXIICollection 13 | tc_source = TAXIICollectionSource(collection) 14 | 15 | # Create filters to retrieve content from Enterprise ATT&CK based on type 16 | filter_objs = {"techniques": Filter("type", "=", "attack-pattern"), 17 | "mitigations": Filter("type", "=", "course-of-action"), 18 | "groups": Filter("type", "=", "intrusion-set"), 19 | "malware": Filter("type", "=", "malware"), 20 | "tools": Filter("type", "=", "tool"), 21 | "relationships": Filter("type", "=", "relationship") 22 | } 23 | 24 | # Retrieve all Enterprise ATT&CK content 25 | for key in filter_objs: 26 | attack[key] = tc_source.query(filter_objs[key]) 27 | 28 | print("%attack = %(") 29 | for t in attack['techniques']: 30 | phase = t['kill_chain_phases'][0]['phase_name'] 31 | for ref in t['external_references']: 32 | if ref.get('source_name', None) == 'mitre-attack': 33 | tactic = ref['external_id'] 34 | #print "%s:%s:%s" % (t['name'], phase, ref['external_id']) 35 | print(tactic + " => %(phase => '" + phase + "', name => '" + t['name'] + "'),") 36 | print(");") 37 | -------------------------------------------------------------------------------- /empire/empire_enrich.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from flask import Flask, request, render_template, make_response 4 | import redis 5 | import datetime 6 | import json 7 | import logging 8 | 9 | # Create the redis object. Make sure that we decode our responses 10 | r = redis.Redis(host='localhost', charset="utf-8", decode_responses=True) 11 | 12 | # Create the Flask app 13 | app = Flask(__name__) 14 | app.debug = True 15 | 16 | 17 | @app.route('/add', methods=['GET']) 18 | def add(): 19 | ''' 20 | Add an agent's extip to the Redis cache 21 | ''' 22 | agent = request.args.get('agent') 23 | extip = request.args.get('extip') 24 | print('Set %s\'s extip to %s' % (agent, extip)) 25 | 26 | 27 | r.hmset(agent, {'extip': extip}) 28 | 29 | return json.dumps({}) 30 | 31 | 32 | @app.route('/update', methods=['POST']) 33 | def update(): 34 | ''' 35 | Update an agent sysinfo checkin details 36 | ''' 37 | 38 | data = request.get_json() 39 | print('json: %s' % data) 40 | 41 | agent = data['agent'] 42 | rdata = r.hgetall(agent) 43 | data.update(rdata) 44 | 45 | print('Set %s\'s sysinfo data to %s' % (agent, data)) 46 | r.hmset(agent, data) 47 | 48 | return json.dumps({}) 49 | 50 | 51 | @app.route('/query', methods=['GET']) 52 | def query(): 53 | ''' 54 | Return a json objet with the corresponding extip. 55 | ''' 56 | agent = request.args.get('agent') 57 | res = r.hgetall(agent) 58 | 59 | print('Agent: %s: %s' % (agent, res)) 60 | 61 | return json.dumps(res) 62 | 63 | 64 | if __name__ == '__main__': 65 | app.run(host='127.0.0.1', port=42424) 66 | -------------------------------------------------------------------------------- /cobaltstrike/filebeat/fields.yml: -------------------------------------------------------------------------------- 1 | - key: csteamserver 2 | type: group 3 | title: Cobalt Strike Teamserver 4 | description: > 5 | Contains event logs from the Cobalt Strike Teamserver 6 | fields: 7 | - name: event 8 | type: text 9 | required: true 10 | description: > 11 | Event type emitted by the teamserver 12 | - name: session 13 | type: text 14 | - name: lastf 15 | type: text 16 | - name: last 17 | type: integer 18 | - name: pbid 19 | type: text 20 | - name: computer 21 | type: text 22 | - name: port 23 | type: integer 24 | - name: pid 25 | type: integer 26 | - name: beacon_id 27 | type: integer 28 | - name: alive 29 | type: boolean 30 | - name: barch 31 | type: keyword 32 | - name: note 33 | type: text 34 | - name: internal 35 | type: text 36 | - name: external 37 | type: text 38 | - name: id 39 | type: integer 40 | - name: ver 41 | type: float 42 | - name: is64 43 | type: integer 44 | - name: os 45 | type: text 46 | - name: event 47 | type: keyword 48 | - name: user 49 | type: keyword 50 | - name: type 51 | type: text 52 | - name: data 53 | type: text 54 | - name: when 55 | type: date 56 | - name: tactic 57 | type: keyword 58 | - name: phase 59 | type: keyword 60 | - name: tactic_name 61 | type: keyword 62 | - name: operator 63 | type: keyword 64 | - name: timestamp 65 | type: date 66 | - name: command 67 | type: text 68 | - name: message 69 | type: text 70 | - name: uri 71 | type: text 72 | - name: method 73 | type: text 74 | - name: ip_address 75 | type: ip 76 | - name: useragent 77 | type: text 78 | - name: response 79 | type: text 80 | - name: response_size 81 | type: integer 82 | - name: file_served 83 | type: text 84 | - name: role 85 | type: keyword 86 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Red Team Telemetry 2 | 3 | A collection of scripts and configurations to enable centralized logging of red team infrastructure. 4 | 5 | ## What's in the repo? 6 | 7 | * cobaltstrike 8 | * filebeat - filebeat configurations for cobalt strike 9 | * json_log.cna - An aggressor script to create a structured json log of beacon events 10 | * There's a known issue where this script will bomb out with a Java StackOverflow error if the logging directory doesn't exist. Be sure to run `mkdir /var/log/cobaltstrike` before you start the logger. 11 | * If there's an event type with no match, the event gets printed to the console and written to the ironically named `notlogged.log`. 12 | * Each log message is tagged with a role based on the username running the script. Example roles might be working, longhaul, test, dev, etc. The role is defined by grabbing the second array element when splitting the name by an underscore. For example, `logbot_test` would create a key:value pair of `"role":"test"` in the log entry. 13 | * The variables `$log_*` are used to enable/disable logging of those event types. Tweak these to your needs. 14 | * The `attack` hash map is generated using the `mitre_cs.py` script. As the ATT&CK Matrix gets updated this will need to be updated. 15 | * event_spy.cna - test script to print all events to the screen 16 | * mitre_cs.py - script to generate aggressor code for enriching tactic IDs with their phase 17 | * packetbeat 18 | * packetbeat.yml - configuration for logging HTTP and DNS C2 19 | 20 | ## Blog Posts 21 | 22 | * Red Team Telemetry Part 1 - https://zachgrace.com/posts/red-team-telemetry-part-1/ 23 | 24 | ## Presentations 25 | 26 | * DerbyCon 8 27 | * [DerbyCon 8 - Red Team Telemetry Slides.pdf](https://github.com/ztgrace/red_team_telemetry/blob/master/DerbyCon_8_-_Red_Team_Telemetry_Slides.pdf) 28 | * https://www.irongeek.com/i.php?page=videos/derbycon8/track-2-14-red-mirror-bringing-telemetry-to-red-teaming-zach-grace 29 | 30 | ## Similar Research 31 | 32 | * CobaltSplunk 33 | * https://vincentyiu.co.uk/cobaltsplunk/ 34 | * https://github.com/vysec/CobaltSplunk 35 | * RedELK 36 | * https://github.com/outflanknl/RedELK 37 | * https://www.youtube.com/watch?v=cwJNaWrOolk 38 | * RedTeamSIEM 39 | * https://github.com/SecurityRiskAdvisors/RedTeamSIEM 40 | * https://www.youtube.com/watch?v=xH1TeVtG1M8&feature=youtu.be 41 | -------------------------------------------------------------------------------- /cobaltstrike/filebeat/teamserver.template.json: -------------------------------------------------------------------------------- 1 | { 2 | "index_patterns": [ 3 | "filebeat-6.2.4-*" 4 | ], 5 | "mappings": { 6 | "doc": { 7 | "_meta": { 8 | "version": "6.2.4" 9 | }, 10 | "date_detection": false, 11 | "dynamic_templates": [ 12 | { 13 | "strings_as_keyword": { 14 | "mapping": { 15 | "ignore_above": 1024, 16 | "type": "keyword" 17 | }, 18 | "match_mapping_type": "string" 19 | } 20 | } 21 | ], 22 | "properties": { 23 | "alive": { 24 | "type": "boolean" 25 | }, 26 | "barch": { 27 | "ignore_above": 1024, 28 | "type": "keyword" 29 | }, 30 | "beacon_id": { 31 | "type": "long" 32 | }, 33 | "command": { 34 | "norms": false, 35 | "type": "text" 36 | }, 37 | "computer": { 38 | "norms": false, 39 | "type": "text" 40 | }, 41 | "data": { 42 | "norms": false, 43 | "type": "text" 44 | }, 45 | "event": { 46 | "ignore_above": 1024, 47 | "type": "keyword" 48 | }, 49 | "external": { 50 | "norms": false, 51 | "type": "text" 52 | }, 53 | "file_served": { 54 | "norms": false, 55 | "type": "text" 56 | }, 57 | "id": { 58 | "type": "long" 59 | }, 60 | "internal": { 61 | "norms": false, 62 | "type": "text" 63 | }, 64 | "ip_address": { 65 | "type": "ip" 66 | }, 67 | "is64": { 68 | "type": "long" 69 | }, 70 | "last": { 71 | "type": "long" 72 | }, 73 | "lastf": { 74 | "norms": false, 75 | "type": "text" 76 | }, 77 | "message": { 78 | "norms": false, 79 | "type": "text" 80 | }, 81 | "method": { 82 | "norms": false, 83 | "type": "text" 84 | }, 85 | "note": { 86 | "norms": false, 87 | "type": "text" 88 | }, 89 | "operator": { 90 | "ignore_above": 1024, 91 | "type": "keyword" 92 | }, 93 | "os": { 94 | "norms": false, 95 | "type": "text" 96 | }, 97 | "pbid": { 98 | "norms": false, 99 | "type": "text" 100 | }, 101 | "phase": { 102 | "ignore_above": 1024, 103 | "type": "keyword" 104 | }, 105 | "pid": { 106 | "type": "long" 107 | }, 108 | "port": { 109 | "type": "long" 110 | }, 111 | "response": { 112 | "norms": false, 113 | "type": "text" 114 | }, 115 | "response_size": { 116 | "type": "long" 117 | }, 118 | "role": { 119 | "ignore_above": 1024, 120 | "type": "keyword" 121 | }, 122 | "session": { 123 | "norms": false, 124 | "type": "text" 125 | }, 126 | "tactic": { 127 | "ignore_above": 1024, 128 | "type": "keyword" 129 | }, 130 | "tactic_name": { 131 | "ignore_above": 1024, 132 | "type": "keyword" 133 | }, 134 | "timestamp": { 135 | "type": "date" 136 | }, 137 | "type": { 138 | "norms": false, 139 | "type": "text" 140 | }, 141 | "uri": { 142 | "norms": false, 143 | "type": "text" 144 | }, 145 | "user": { 146 | "ignore_above": 1024, 147 | "type": "keyword" 148 | }, 149 | "useragent": { 150 | "norms": false, 151 | "type": "text" 152 | }, 153 | "ver": { 154 | "type": "float" 155 | }, 156 | "when": { 157 | "type": "date" 158 | } 159 | } 160 | } 161 | }, 162 | "order": 1, 163 | "settings": { 164 | "index": { 165 | "mapping": { 166 | "total_fields": { 167 | "limit": 10000 168 | } 169 | }, 170 | "number_of_routing_shards": 30, 171 | "refresh_interval": "5s" 172 | } 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /empire/logstash/empire.conf: -------------------------------------------------------------------------------- 1 | input { 2 | beats { 3 | port => 5044 4 | ssl => true 5 | ssl_certificate => "/etc/logstash/logstash.crt" 6 | ssl_key => "/etc/logstash/pkcs8_key.pem" 7 | ssl_verify_mode => "force_peer" 8 | ssl_certificate_authorities => ["/etc/logstash/ca.crt"] 9 | } 10 | } 11 | 12 | # 2019-01-16 20:37:13 empire : {"print": true, "message": "[*] Empire starting up..."} 13 | filter { 14 | grok { 15 | match => { "message" => " empire : %{GREEDYDATA:json}$" } 16 | } 17 | } 18 | 19 | # Parse the date 20 | filter { 21 | grok { 22 | match => ["message", "%{TIMESTAMP_ISO8601:timestamp}"] 23 | } 24 | 25 | # date { 26 | # match => [ "timestamp", "ISO8601", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm:ss"] 27 | # target => "@timestamp" 28 | # add_tag => [ "tsmatch" ] 29 | # } 30 | } 31 | 32 | # 2019-01-26 17:24:32 agents/JRACRT9C : {"print": false, "message": "[*] handle_agent_data(): sessionID JRACRT9C issued a TASKING_REQUEST"} 33 | filter { 34 | grok { 35 | match => { "message" => " agents/%{USERNAME:agent} : %{GREEDYDATA:json}$" } 36 | } 37 | } 38 | 39 | # 2019-01-26 17:24:22 agents/JRACRT9C/python/collection/linux/pillage_user : {"print": true, "message": "[*] Tasked agent JRACRT9C to run module python/collection/linux/pillage_user", "options": {"AllUsers": {"Required": false, "Description": "Switch. Run for all users (needs root privileges!)", "Value": "False"}, "Sleep": {"Required": false, "Description": "Switch. Sleep the agent's normal interval between downloads, otherwise use one blast.", "Value": "True"}, "Agent": {"Required": true, "Description": "Agent to execute module on.", "Value": "JRACRT9C"}}} 40 | filter { 41 | grok { 42 | match => { "message" => " agents/%{USERNAME:agent}/(?[a-z/_]+) : %{GREEDYDATA:json}$" } 43 | } 44 | } 45 | 46 | # 2019-01-26 17:24:27 listeners/http/http : {"print": false, "message": "[*] GET request for 192.168.2.131:80/login/process.php from 192.168.2.131"} 47 | filter { 48 | grok { 49 | match => { "message" => " listeners/%{USERNAME:listener_type}/%{USERNAME:listener} : %{GREEDYDATA:json}$" } 50 | } 51 | } 52 | 53 | # 2019-01-28 09:00:32 agents/7HJ0QYZ5 : {"print": false, "message": "[!] Nonce verified: agent 7HJ0QYZ5 posted valid sysinfo checkin format: 9651055890329090|http://192.168.2.131:80||root|kali|127.0.1.1|Linux,kali,4.17.0-kali1-amd64,#1 SMP Debian 4.17.8-1kali1 (2018-07-24),x86_64|True|/usr/bin/python|56767|python|2.7"} 54 | filter { 55 | grok { 56 | match => { "message" => "\|%{USERNAME:username}\|%{USERNAME:hostname}\|(?[0-9\.]+)\|(?[a-zA-Z0-9 ,#\.\(\)-_]+)\|[a-zA-Z]+\|(?[a-zA-Z0-9\/-]+)\|(?[0-9]+)\|(?[a-zA-Z]+)\|(?[0-9\.]+)" } 57 | } 58 | } 59 | 60 | filter { 61 | grok { 62 | match => { "message" => 'Agent [A-Z0-9]+ from (?[0-9\.]+) posted public key"}' } 63 | } 64 | } 65 | 66 | filter { 67 | if [extip] { 68 | rest { 69 | request => { 70 | url => "http://127.0.0.1:42424/add?agent=%{agent}&extip=%{extip}" 71 | } 72 | json => true 73 | target => "dummy" 74 | } 75 | } 76 | } 77 | 78 | filter { 79 | if [process] { 80 | rest { 81 | request => { 82 | url => "http://127.0.0.1:42424/update" 83 | method => "post" 84 | headers => { 85 | "Content-Type" => "application/json" 86 | } 87 | params => { 88 | "agent" => "%{agent}" 89 | "hostname" => "%{hostname}" 90 | "process" => "%{process}" 91 | "lang_version" => "%{lang_version}" 92 | "OS" => "%{OS}" 93 | "pid" => "%{pid}" 94 | "language" => "%{language}" 95 | "internalip" => "%{internalip}" 96 | "username" => "%{username}" 97 | } 98 | } 99 | json => true 100 | target => "dummy" 101 | } 102 | } 103 | } 104 | 105 | filter { 106 | if [agent] { 107 | rest { 108 | request => { 109 | url => "http://127.0.0.1:42424/query?agent=%{agent}" 110 | } 111 | json => true 112 | target => "implant" 113 | } 114 | } 115 | } 116 | 117 | filter { 118 | json{ 119 | source => "json" 120 | target => "empire" 121 | } 122 | } 123 | 124 | output { 125 | elasticsearch { 126 | hosts => ["http://localhost:9200"] 127 | index => "%{[@metadata][beat]}-%{[@metadata][version]}-%{+YYYY.MM.dd}" 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /cobaltstrike/json_log.cna: -------------------------------------------------------------------------------- 1 | # json_log.cna by Zach Grace (@ztgrace) 2 | # An aggressor script to create a structured json log of beacon events 3 | # Be sure to heed the warnings in the README for proper operation 4 | 5 | 6 | # Config 7 | $logdir = "/var/log/cobaltstrike/"; 8 | $notlogged = "notlogged.log"; 9 | 10 | # The role is pulled from the nick, logbot_working role = working 11 | $role = split('_', data_query("metadata")['nick'])[1]; 12 | 13 | # enable/disable logging of event types 14 | $log_beacons = false; 15 | $log_beacon_input = true; 16 | $log_beacon_tasked = true; 17 | $log_beacon_checkin = true; 18 | $log_beacon_error = true; 19 | $log_beacon_output = true; 20 | $log_archives = true; 21 | $log_web_hit = true; 22 | $log_weblog = false; 23 | $log_beaconlog = false; 24 | $log_beacon_indicator = true; 25 | $log_event_beacon_initial = true; 26 | $log_beacon_initial = true; 27 | 28 | ################################################################################################ 29 | # Generated data from the mitre_cs.py script 30 | # Eventually this should probably be a logstash plugin 31 | 32 | %attack = %( 33 | T1163 => %(phase => 'persistence', name => 'Rc.common'), 34 | T1027 => %(phase => 'defense-evasion', name => 'Obfuscated Files or Information'), 35 | T1189 => %(phase => 'initial-access', name => 'Drive-by Compromise'), 36 | T1074 => %(phase => 'collection', name => 'Data Staged'), 37 | T1105 => %(phase => 'command-and-control', name => 'Remote File Copy'), 38 | T1134 => %(phase => 'defense-evasion', name => 'Access Token Manipulation'), 39 | T1069 => %(phase => 'discovery', name => 'Permission Groups Discovery'), 40 | T1215 => %(phase => 'persistence', name => 'Kernel Modules and Extensions'), 41 | T1186 => %(phase => 'defense-evasion', name => 'Process Doppelgänging'), 42 | T1089 => %(phase => 'defense-evasion', name => 'Disabling Security Tools'), 43 | T1014 => %(phase => 'defense-evasion', name => 'Rootkit'), 44 | T1092 => %(phase => 'command-and-control', name => 'Communication Through Removable Media'), 45 | T1122 => %(phase => 'defense-evasion', name => 'Component Object Model Hijacking'), 46 | T1150 => %(phase => 'defense-evasion', name => 'Plist Modification'), 47 | T1143 => %(phase => 'defense-evasion', name => 'Hidden Window'), 48 | T1140 => %(phase => 'defense-evasion', name => 'Deobfuscate/Decode Files or Information'), 49 | T1198 => %(phase => 'defense-evasion', name => 'SIP and Trust Provider Hijacking'), 50 | T1068 => %(phase => 'privilege-escalation', name => 'Exploitation for Privilege Escalation'), 51 | T1139 => %(phase => 'credential-access', name => 'Bash History'), 52 | T1117 => %(phase => 'defense-evasion', name => 'Regsvr32'), 53 | T1094 => %(phase => 'command-and-control', name => 'Custom Command and Control Protocol'), 54 | T1146 => %(phase => 'defense-evasion', name => 'Clear Command History'), 55 | T1173 => %(phase => 'execution', name => 'Dynamic Data Exchange'), 56 | T1167 => %(phase => 'credential-access', name => 'Securityd Memory'), 57 | T1084 => %(phase => 'persistence', name => 'Windows Management Instrumentation Event Subscription'), 58 | T1002 => %(phase => 'exfiltration', name => 'Data Compressed'), 59 | T1049 => %(phase => 'discovery', name => 'System Network Connections Discovery'), 60 | T1063 => %(phase => 'discovery', name => 'Security Software Discovery'), 61 | T1060 => %(phase => 'persistence', name => 'Registry Run Keys / Start Folder'), 62 | T1184 => %(phase => 'lateral-movement', name => 'SSH Hijacking'), 63 | T1076 => %(phase => 'lateral-movement', name => 'Remote Desktop Protocol'), 64 | T1006 => %(phase => 'defense-evasion', name => 'File System Logical Offsets'), 65 | T1181 => %(phase => 'defense-evasion', name => 'Extra Window Memory Injection'), 66 | T1072 => %(phase => 'execution', name => 'Third-party Software'), 67 | T1093 => %(phase => 'defense-evasion', name => 'Process Hollowing'), 68 | T1164 => %(phase => 'persistence', name => 'Re-opened Applications'), 69 | T1118 => %(phase => 'defense-evasion', name => 'InstallUtil'), 70 | T1197 => %(phase => 'defense-evasion', name => 'BITS Jobs'), 71 | T1065 => %(phase => 'command-and-control', name => 'Uncommonly Used Port'), 72 | T1124 => %(phase => 'discovery', name => 'System Time Discovery'), 73 | T1099 => %(phase => 'defense-evasion', name => 'Timestomp'), 74 | T1032 => %(phase => 'command-and-control', name => 'Standard Cryptographic Protocol'), 75 | T1043 => %(phase => 'command-and-control', name => 'Commonly Used Port'), 76 | T1190 => %(phase => 'initial-access', name => 'Exploit Public-Facing Application'), 77 | T1073 => %(phase => 'defense-evasion', name => 'DLL Side-Loading'), 78 | T1207 => %(phase => 'defense-evasion', name => 'DCShadow'), 79 | T1013 => %(phase => 'persistence', name => 'Port Monitors'), 80 | T1216 => %(phase => 'defense-evasion', name => 'Signed Script Proxy Execution'), 81 | T1127 => %(phase => 'defense-evasion', name => 'Trusted Developer Utilities'), 82 | T1075 => %(phase => 'lateral-movement', name => 'Pass the Hash'), 83 | T1104 => %(phase => 'command-and-control', name => 'Multi-Stage Channels'), 84 | T1079 => %(phase => 'command-and-control', name => 'Multilayer Encryption'), 85 | T1219 => %(phase => 'command-and-control', name => 'Remote Access Tools'), 86 | T1035 => %(phase => 'execution', name => 'Service Execution'), 87 | T1165 => %(phase => 'persistence', name => 'Startup Items'), 88 | T1071 => %(phase => 'command-and-control', name => 'Standard Application Layer Protocol'), 89 | T1050 => %(phase => 'persistence', name => 'New Service'), 90 | T1052 => %(phase => 'exfiltration', name => 'Exfiltration Over Physical Medium'), 91 | T1129 => %(phase => 'execution', name => 'Execution through Module Load'), 92 | T1066 => %(phase => 'defense-evasion', name => 'Indicator Removal from Tools'), 93 | T1193 => %(phase => 'initial-access', name => 'Spearphishing Attachment'), 94 | T1095 => %(phase => 'command-and-control', name => 'Standard Non-Application Layer Protocol'), 95 | T1110 => %(phase => 'credential-access', name => 'Brute Force'), 96 | T1020 => %(phase => 'exfiltration', name => 'Automated Exfiltration'), 97 | T1132 => %(phase => 'command-and-control', name => 'Data Encoding'), 98 | T1202 => %(phase => 'defense-evasion', name => 'Indirect Command Execution'), 99 | T1053 => %(phase => 'execution', name => 'Scheduled Task'), 100 | T1083 => %(phase => 'discovery', name => 'File and Directory Discovery'), 101 | T1205 => %(phase => 'command-and-control', name => 'Port Knocking'), 102 | T1212 => %(phase => 'credential-access', name => 'Exploitation for Credential Access'), 103 | T1195 => %(phase => 'initial-access', name => 'Supply Chain Compromise'), 104 | T1058 => %(phase => 'persistence', name => 'Service Registry Permissions Weakness'), 105 | T1088 => %(phase => 'defense-evasion', name => 'Bypass User Account Control'), 106 | T1192 => %(phase => 'initial-access', name => 'Spearphishing Link'), 107 | T1176 => %(phase => 'persistence', name => 'Browser Extensions'), 108 | T1137 => %(phase => 'persistence', name => 'Office Application Startup'), 109 | T1196 => %(phase => 'defense-evasion', name => 'Control Panel Items'), 110 | T1209 => %(phase => 'persistence', name => 'Time Providers'), 111 | T1217 => %(phase => 'discovery', name => 'Browser Bookmark Discovery'), 112 | T1056 => %(phase => 'collection', name => 'Input Capture'), 113 | T1188 => %(phase => 'command-and-control', name => 'Multi-hop Proxy'), 114 | T1017 => %(phase => 'lateral-movement', name => 'Application Deployment Software'), 115 | T1045 => %(phase => 'defense-evasion', name => 'Software Packing'), 116 | T1051 => %(phase => 'lateral-movement', name => 'Shared Webroot'), 117 | T1200 => %(phase => 'initial-access', name => 'Hardware Additions'), 118 | T1081 => %(phase => 'credential-access', name => 'Credentials in Files'), 119 | T1077 => %(phase => 'lateral-movement', name => 'Windows Admin Shares'), 120 | T1040 => %(phase => 'credential-access', name => 'Network Sniffing'), 121 | T1123 => %(phase => 'collection', name => 'Audio Capture'), 122 | T1103 => %(phase => 'persistence', name => 'AppInit DLLs'), 123 | T1153 => %(phase => 'execution', name => 'Source'), 124 | T1005 => %(phase => 'collection', name => 'Data from Local System'), 125 | T1028 => %(phase => 'execution', name => 'Windows Remote Management'), 126 | T1090 => %(phase => 'command-and-control', name => 'Connection Proxy'), 127 | T1070 => %(phase => 'defense-evasion', name => 'Indicator Removal on Host'), 128 | T1101 => %(phase => 'persistence', name => 'Security Support Provider'), 129 | T1030 => %(phase => 'exfiltration', name => 'Data Transfer Size Limits'), 130 | T1159 => %(phase => 'persistence', name => 'Launch Agent'), 131 | T1218 => %(phase => 'defense-evasion', name => 'Signed Binary Proxy Execution'), 132 | T1111 => %(phase => 'credential-access', name => 'Two-Factor Authentication Interception'), 133 | T1025 => %(phase => 'collection', name => 'Data from Removable Media'), 134 | T1120 => %(phase => 'discovery', name => 'Peripheral Device Discovery'), 135 | T1055 => %(phase => 'defense-evasion', name => 'Process Injection'), 136 | T1047 => %(phase => 'execution', name => 'Windows Management Instrumentation'), 137 | T1204 => %(phase => 'execution', name => 'User Execution'), 138 | T1115 => %(phase => 'collection', name => 'Clipboard Data'), 139 | T1154 => %(phase => 'execution', name => 'Trap'), 140 | T1097 => %(phase => 'lateral-movement', name => 'Pass the Ticket'), 141 | T1096 => %(phase => 'defense-evasion', name => 'NTFS File Attributes'), 142 | T1160 => %(phase => 'persistence', name => 'Launch Daemon'), 143 | T1107 => %(phase => 'defense-evasion', name => 'File Deletion'), 144 | T1203 => %(phase => 'execution', name => 'Exploitation for Client Execution'), 145 | T1147 => %(phase => 'defense-evasion', name => 'Hidden Users'), 146 | T1087 => %(phase => 'discovery', name => 'Account Discovery'), 147 | T1048 => %(phase => 'exfiltration', name => 'Exfiltration Over Alternative Protocol'), 148 | T1210 => %(phase => 'lateral-movement', name => 'Exploitation of Remote Services'), 149 | T1112 => %(phase => 'defense-evasion', name => 'Modify Registry'), 150 | T1024 => %(phase => 'command-and-control', name => 'Custom Cryptographic Protocol'), 151 | T1214 => %(phase => 'credential-access', name => 'Credentials in Registry'), 152 | T1201 => %(phase => 'discovery', name => 'Password Policy Discovery'), 153 | T1042 => %(phase => 'persistence', name => 'Change Default File Association'), 154 | T1021 => %(phase => 'lateral-movement', name => 'Remote Services'), 155 | T1091 => %(phase => 'lateral-movement', name => 'Replication Through Removable Media'), 156 | T1171 => %(phase => 'credential-access', name => 'LLMNR/NBT-NS Poisoning'), 157 | T1172 => %(phase => 'command-and-control', name => 'Domain Fronting'), 158 | T1125 => %(phase => 'collection', name => 'Video Capture'), 159 | T1133 => %(phase => 'persistence', name => 'External Remote Services'), 160 | T1211 => %(phase => 'defense-evasion', name => 'Exploitation for Defense Evasion'), 161 | T1179 => %(phase => 'credential-access', name => 'Hooking'), 162 | T1016 => %(phase => 'discovery', name => 'System Network Configuration Discovery'), 163 | T1142 => %(phase => 'credential-access', name => 'Keychain'), 164 | T1119 => %(phase => 'collection', name => 'Automated Collection'), 165 | T1109 => %(phase => 'defense-evasion', name => 'Component Firmware'), 166 | T1106 => %(phase => 'execution', name => 'Execution through API'), 167 | T1057 => %(phase => 'discovery', name => 'Process Discovery'), 168 | T1026 => %(phase => 'command-and-control', name => 'Multiband Communication'), 169 | T1175 => %(phase => 'lateral-movement', name => 'Distributed Component Object Model'), 170 | T1078 => %(phase => 'defense-evasion', name => 'Valid Accounts'), 171 | T1138 => %(phase => 'persistence', name => 'Application Shimming'), 172 | T1174 => %(phase => 'credential-access', name => 'Password Filter DLL'), 173 | T1033 => %(phase => 'discovery', name => 'System Owner/User Discovery'), 174 | T1169 => %(phase => 'privilege-escalation', name => 'Sudo'), 175 | T1067 => %(phase => 'persistence', name => 'Bootkit'), 176 | T1102 => %(phase => 'command-and-control', name => 'Web Service'), 177 | T1130 => %(phase => 'defense-evasion', name => 'Install Root Certificate'), 178 | T1168 => %(phase => 'persistence', name => 'Local Job Scheduling'), 179 | T1001 => %(phase => 'command-and-control', name => 'Data Obfuscation'), 180 | T1036 => %(phase => 'defense-evasion', name => 'Masquerading'), 181 | T1038 => %(phase => 'defense-evasion', name => 'DLL Search Order Hijacking'), 182 | T1170 => %(phase => 'defense-evasion', name => 'Mshta'), 183 | T1183 => %(phase => 'defense-evasion', name => 'Image File Execution Options Injection'), 184 | T1007 => %(phase => 'discovery', name => 'System Service Discovery'), 185 | T1151 => %(phase => 'defense-evasion', name => 'Space after Filename'), 186 | T1126 => %(phase => 'defense-evasion', name => 'Network Share Connection Removal'), 187 | T1003 => %(phase => 'credential-access', name => 'Credential Dumping'), 188 | T1145 => %(phase => 'credential-access', name => 'Private Keys'), 189 | T1022 => %(phase => 'exfiltration', name => 'Data Encrypted'), 190 | T1149 => %(phase => 'defense-evasion', name => 'LC_MAIN Hijacking'), 191 | T1141 => %(phase => 'credential-access', name => 'Input Prompt'), 192 | T1034 => %(phase => 'persistence', name => 'Path Interception'), 193 | T1012 => %(phase => 'discovery', name => 'Query Registry'), 194 | T1116 => %(phase => 'defense-evasion', name => 'Code Signing'), 195 | T1135 => %(phase => 'discovery', name => 'Network Share Discovery'), 196 | T1100 => %(phase => 'persistence', name => 'Web Shell'), 197 | T1191 => %(phase => 'defense-evasion', name => 'CMSTP'), 198 | T1121 => %(phase => 'defense-evasion', name => 'Regsvcs/Regasm'), 199 | T1044 => %(phase => 'persistence', name => 'File System Permissions Weakness'), 200 | T1113 => %(phase => 'collection', name => 'Screen Capture'), 201 | T1009 => %(phase => 'defense-evasion', name => 'Binary Padding'), 202 | T1082 => %(phase => 'discovery', name => 'System Information Discovery'), 203 | T1155 => %(phase => 'execution', name => 'AppleScript'), 204 | T1085 => %(phase => 'defense-evasion', name => 'Rundll32'), 205 | T1046 => %(phase => 'discovery', name => 'Network Service Scanning'), 206 | T1010 => %(phase => 'discovery', name => 'Application Window Discovery'), 207 | T1158 => %(phase => 'defense-evasion', name => 'Hidden Files and Directories'), 208 | T1041 => %(phase => 'exfiltration', name => 'Exfiltration Over Command and Control Channel'), 209 | T1185 => %(phase => 'collection', name => 'Man in the Browser'), 210 | T1208 => %(phase => 'credential-access', name => 'Kerberoasting'), 211 | T1086 => %(phase => 'execution', name => 'PowerShell'), 212 | T1037 => %(phase => 'lateral-movement', name => 'Logon Scripts'), 213 | T1059 => %(phase => 'execution', name => 'Command-Line Interface'), 214 | T1187 => %(phase => 'credential-access', name => 'Forced Authentication'), 215 | T1161 => %(phase => 'persistence', name => 'LC_LOAD_DYLIB Addition'), 216 | T1039 => %(phase => 'collection', name => 'Data from Network Shared Drive'), 217 | T1114 => %(phase => 'collection', name => 'Email Collection'), 218 | T1054 => %(phase => 'defense-evasion', name => 'Indicator Blocking'), 219 | T1108 => %(phase => 'defense-evasion', name => 'Redundant Access'), 220 | T1062 => %(phase => 'persistence', name => 'Hypervisor'), 221 | T1152 => %(phase => 'defense-evasion', name => 'Launchctl'), 222 | T1206 => %(phase => 'privilege-escalation', name => 'Sudo Caching'), 223 | T1180 => %(phase => 'persistence', name => 'Screensaver'), 224 | T1011 => %(phase => 'exfiltration', name => 'Exfiltration Over Other Network Medium'), 225 | T1166 => %(phase => 'privilege-escalation', name => 'Setuid and Setgid'), 226 | T1080 => %(phase => 'lateral-movement', name => 'Taint Shared Content'), 227 | T1064 => %(phase => 'defense-evasion', name => 'Scripting'), 228 | T1128 => %(phase => 'persistence', name => 'Netsh Helper DLL'), 229 | T1162 => %(phase => 'persistence', name => 'Login Item'), 230 | T1182 => %(phase => 'persistence', name => 'AppCert DLLs'), 231 | T1199 => %(phase => 'initial-access', name => 'Trusted Relationship'), 232 | T1136 => %(phase => 'persistence', name => 'Create Account'), 233 | T1213 => %(phase => 'collection', name => 'Data from Information Repositories'), 234 | T1023 => %(phase => 'persistence', name => 'Shortcut Modification'), 235 | T1177 => %(phase => 'execution', name => 'LSASS Driver'), 236 | T1098 => %(phase => 'credential-access', name => 'Account Manipulation'), 237 | T1156 => %(phase => 'persistence', name => '.bash_profile and .bashrc'), 238 | T1015 => %(phase => 'persistence', name => 'Accessibility Features'), 239 | T1131 => %(phase => 'persistence', name => 'Authentication Package'), 240 | T1008 => %(phase => 'command-and-control', name => 'Fallback Channels'), 241 | T1148 => %(phase => 'defense-evasion', name => 'HISTCONTROL'), 242 | T1144 => %(phase => 'defense-evasion', name => 'Gatekeeper Bypass'), 243 | T1061 => %(phase => 'execution', name => 'Graphical User Interface'), 244 | T1004 => %(phase => 'persistence', name => 'Winlogon Helper DLL'), 245 | T1157 => %(phase => 'persistence', name => 'Dylib Hijacking'), 246 | T1178 => %(phase => 'privilege-escalation', name => 'SID-History Injection'), 247 | T1018 => %(phase => 'discovery', name => 'Remote System Discovery'), 248 | T1019 => %(phase => 'persistence', name => 'System Firmware'), 249 | T1194 => %(phase => 'initial-access', name => 'Spearphishing via Service'), 250 | T1031 => %(phase => 'persistence', name => 'Modify Existing Service'), 251 | T1029 => %(phase => 'exfiltration', name => 'Scheduled Transfer'), 252 | ); 253 | ################################################################################################ 254 | 255 | on * { 256 | # Skip heartbeats 257 | if ('heartbeat_*' iswm $1) { 258 | return; 259 | } 260 | else if ($1 eq 'interfaces') { 261 | return; 262 | } 263 | else if ($1 eq "beacons") 264 | { 265 | if (-istrue $log_beacons) { 266 | # beacon status 267 | # array(beaconid => %datahash, beaconid => %datahash) 268 | $data = subarray(@_, 1); 269 | # array of beacons 270 | foreach $bindex => $beacon ($data) { 271 | # beaconid => %datahash 272 | foreach $beacon_id => $bdata ($beacon) { 273 | %entry = %(event => $1, beacon_id => $beacon_id); 274 | foreach $key => $value ($bdata) { 275 | %entry[$key] = $value; 276 | } 277 | %entry['timestamp'] = ticks(); 278 | log(json_encode(%entry)); 279 | } 280 | } 281 | } 282 | } 283 | else if ($1 eq "beacon_input") { 284 | if (-istrue $log_beacon_input) { 285 | # beacon_input events 286 | # [beacon_input]: @('87653', 'ztg', 'shell whoami', 1526394689394L) 287 | $data = subarray(@_, 1); 288 | $entry = json_encode(%(event => $1, beacon_id => $data[0], operator => $data[1], command => $data[2], timestamp => $data[3])); 289 | log($entry); 290 | } 291 | } 292 | else if ($1 eq "beacon_tasked" || $1 eq "beacon_checkin" || $1 eq "beacon_output" || $1 eq "beacon_error" || $1 eq "beacon_output_ps" || $1 eq "beacon_output_ls") { 293 | if (-istrue $log_beacon_tasked || -istrue $log_beacon_checkin || -istrue $log_beacon_output || -istrue $log_beacon_error) { 294 | # [beacon_tasked]: @('87653', 'Tasked beacon to run: whoami', 1526394689395L) 295 | # [beacon_checkin]: @('87653', 'host called home, sent: 37 bytes', 1526394691194L) 296 | # [beacon_output]: @('87653', 'received output: foo\bar', 1526394695375L) 297 | $data = subarray(@_, 1); 298 | $entry = json_encode(%(event => $1, beacon_id => $data[0], message => $data[1], timestamp => $data[2])); 299 | log($entry); 300 | } 301 | } 302 | else if ($1 eq "beacon_indicator") { 303 | if (-istrue $log_beacon_indicator) { 304 | #@('beacon_indicator', '59349', 'ztg', 'service: \\127.0.0.1 upd72cae', 1528234777704L) 305 | $data = subarray(@_, 1); 306 | $entry = json_encode(%(event => 'beacon_indicator', beacon_id => $data[0], operator => $data[1], message => $data[2], timestamp => $data[3])); 307 | log($entry); 308 | } 309 | } 310 | else if ($1 eq "event_beacon_initial") { 311 | if (-istrue $log_event_beacon_initial) { 312 | # @('event_beacon_initial', 'user123@192.168.56.1 (COMPUTER1)', 1530299679446L, 'user123@192.168.56.1 (COMPUTER1)', 1530299679446L) 313 | $data = subarray(@_, 1); 314 | $user = split("@", $data[0])[0]; 315 | $ip = split(" ", split("@", $data[0])[1])[0]; 316 | $host = replace(split("[(]", $data[0])[1], "[)]", ""); 317 | $entry = json_encode(%(event => "event_beacon_initial", hostname => $host, user => $user, ip => $ip, timestamp => $data[1])); 318 | log($entry); 319 | } 320 | } 321 | else if ($1 eq "beacon_initial" || $1 eq "beacon_initial_empty") { 322 | if (-istrue $log_beacon_initial) { 323 | #@('beacon_initial', '12608') 324 | #@('beacon_initial_empty', '12608') 325 | $data = subarray(@_, 1); 326 | $entry = json_encode(%(event => $1, beacon_id => $data[0], timestamp => ticks())); 327 | log($entry); 328 | 329 | } 330 | } 331 | else if ($1 eq "archives") { 332 | if (-istrue $log_archives) { 333 | # [archives]: @(%(data => 'shell whoami', type => 'input', bid => '87653', when => 1526394689394L)) 334 | # [archives]: @(%(data => 'run: whoami', type => 'task', bid => '87653', when => 1526394689395L, tactic => 'T1059')) 335 | # [archives]: @(%(data => 'run: whoami', type => 'task', bid => '87653', when => 1526394689395L, tactic => 'T1003, T1055, T1093')) 336 | # [archives]: @(%(data => 'host called home, sent: 37 bytes', type => 'checkin', bid => '87653', when => 1526394691194L)) 337 | $data = subarray(@_, 1)[0]; 338 | $beacon_id = $data['bid']; 339 | if ($beacon_id == $null) { 340 | $beacon_id = 0; 341 | } 342 | %entry = %(event => 'beacon_indicator', beacon_id => $beacon_id, type => $data['type'], message => $data['data'], when => $data['when'], timestamp => ticks()); 343 | if ("tactic" in $data) { 344 | $tactics = split(", ", $data['tactic']); 345 | # Create individual entries for each tactic 346 | foreach $tactic ($tactics) { 347 | %entry['tactic'] = $tactic; 348 | %entry['phase'] = %attack[$tactic]["phase"]; 349 | %entry['tactic_name'] = %attack[$tactic]["name"]; 350 | log(json_encode(%entry)); 351 | } 352 | } 353 | else { 354 | log(json_encode(%entry)); 355 | } 356 | } 357 | } 358 | else if ($1 eq "beaconlog") { 359 | if (-istrue $log_beaconlog) { 360 | # skipping for now as the data is duplicated in the beacon_* events 361 | return; 362 | } 363 | } 364 | else if ($1 eq "web_hit") { 365 | if (-istrue $log_web_hit) { 366 | $data = subarray(@_, 1); 367 | $entry = json_encode(%(event => 'web_hit', method => $data[0], uri => $data[1], ip_address => $data[2], useragent => $data[3], response => $data[4], response_size => $data[5], file_served => $data[6], unknown => $data[7], timestamp => $data[8])); 368 | log($entry); 369 | } 370 | } 371 | else if ($1 eq "event_newsite") { 372 | $data = subarray(@_, 1); 373 | log(json_encode(%(event => "event_newsite", operator => $data[0], message => $data[1], timestamp => $data[2]))); 374 | } 375 | else if ($1 eq "weblog" || $1 eq "c2info" || $1 eq "sessions" || $1 eq "targets") { 376 | # Skipping as we're already getting this data with packetbeat 377 | return; 378 | } 379 | else { 380 | println($1 . " not logged"); 381 | notLogged(@_); 382 | } 383 | } 384 | 385 | sub log { 386 | $logfile = $logdir . "/teamserver-" . $role . "-" . formatDate("yyyy.MM.dd") . '.json'; 387 | if (-canwrite $logfile) { 388 | $h = openf(">>" . $logfile); 389 | println($h, $1); 390 | closef($h); 391 | } 392 | else { 393 | createNewFile($logfile); 394 | log($@_) 395 | } 396 | } 397 | 398 | # Accepts a hash and returns a json encoded string 399 | sub json_encode { 400 | %data = $1; 401 | $json = "{"; 402 | foreach $key (keys(%data)) { 403 | $json = $json . '"' . $key . '":"' . escape(%data[$key]) . '",'; 404 | } 405 | $json = $json . '"role":"' . $role . '",'; 406 | $json = $json . "}"; 407 | $json = replace($json, ",}$", "}"); 408 | return $json; 409 | } 410 | 411 | sub notLogged { 412 | println($1); 413 | if (-canwrite $notlogged) { 414 | $h = openf(">>" . $notlogged); 415 | println($h, $1); 416 | closef($h); 417 | } 418 | else { 419 | println("Unable to write to log file " . $notlogged); 420 | } 421 | } 422 | 423 | # escape special chars for json output 424 | sub escape { 425 | $escaped = replace($1, '[\\\\]', '\\\\\\\\'); 426 | $escaped = replace($escaped, "\n", "\\\\n"); 427 | $escaped = replace($escaped, "\r", "\\\\r"); 428 | $escaped = replace($escaped, "\t", "\\\\t"); 429 | return $escaped; 430 | } 431 | --------------------------------------------------------------------------------