description: Pipeline for parsing Malware Bazaar Threat Intel
processors:

####################
# Event ECS fields #
####################
- set:
    field: event.ingested
    value: '{{_ingest.timestamp}}'
- set:
    field: event.kind
    value: enrichment
- set:
    field: event.category
    value: threat
- set:
    field: event.type
    value: indicator

######################
# General ECS fields #
######################
- rename:
    field: json
    target_field: threatintel.malwarebazaar
    ignore_missing: true

#####################
# Threat ECS Fields #
#####################
- date:
    field: threatintel.malwarebazaar.first_seen
    target_field: threatintel.indicator.first_seen
    formats:
      - "yyyy-MM-dd HH:mm:ss z"
      - "yyyy-MM-dd HH:mm:ss Z"
      - "yyyy-MM-dd HH:mm:ss"
    if: "ctx?.threatintel?.malwarebazaar.first_seen != null"
- date:
    field: threatintel.malwarebazaar.last_seen
    target_field: threatintel.indicator.last_seen
    formats:
      - "yyyy-MM-dd HH:mm:ss z"
      - "yyyy-MM-dd HH:mm:ss Z"
      - "yyyy-MM-dd HH:mm:ss"
    if: "ctx?.threatintel?.malwarebazaar.last_seen != null"
- set:
    field: threatintel.indicator.type
    value: file
- rename:
    field: threatintel.malwarebazaar.file_name
    target_field: threatintel.indicator.file.name
    ignore_missing: true
- rename:
    field: threatintel.malwarebazaar.file_type_mime
    target_field: threatintel.indicator.file.mime_type
    ignore_missing: true
- rename:
    field: threatintel.malwarebazaar.reporter
    target_field: threatintel.indicator.provider
    ignore_missing: true
- rename:
    field: threatintel.malwarebazaar.origin_country
    target_field: threatintel.indicator.geo.country_iso_code
    ignore_missing: true
- rename:
    field: threatintel.malwarebazaar.signature
    target_field: threatintel.indicator.signature
    ignore_missing: true
- foreach:
    field: threatintel.malwarebazaar.code_sign
    ignore_missing: true
    processor:
      rename:
        field: subject_cn
        target_field: threatintel.indicator.file.x509.subject.common_name
      rename:
        field: issuer_cn
        target_field: threatintel.indicator.file.x509.issuer.common_name
      rename:
        field: algorithm
        target_field: threatintel.indicator.file.x509.public_key_algorithm
      rename:
        field: valid_from
        target_field: threatintel.indicator.file.x509.not_before
      rename:
        field: valid_to
        target_field: threatintel.indicator.file.x509.not_after
      rename:
        field: serial_number
        target_field: threatintel.indicator.file.x509.serial_number
- rename:
    field: threatintel.malwarebazaar.file_size
    target_field: threatintel.indicator.file.size
    ignore_missing: true
- rename:
    field: threatintel.malwarebazaar.file_type
    target_field: threatintel.indicator.file.extension
    ignore_missing: true
- rename:
    field: threatintel.malwarebazaar.md5_hash
    target_field: threatintel.indicator.file.hash.md5
    ignore_missing: true
- rename:
    field: threatintel.malwarebazaar.sha256_hash
    target_field: threatintel.indicator.file.hash.sha256
    ignore_missing: true
- rename:
    field: threatintel.malwarebazaar.sha1_hash
    target_field: threatintel.indicator.file.hash.sha1
    ignore_missing: true
- rename:
    field: threatintel.malwarebazaar.sha3_384_hash
    target_field: threatintel.indicator.file.hash.sha384
    ignore_missing: true
- rename:
    field: threatintel.malwarebazaar.imphash
    target_field: threatintel.indicator.file.pe.imphash
    ignore_missing: true
- rename:
    field: threatintel.malwarebazaar.ssdeep
    target_field: threatintel.indicator.file.hash.ssdeep
    ignore_missing: true
- rename:
    field: threatintel.malwarebazaar.tlsh
    target_field: threatintel.indicator.file.hash.tlsh
    ignore_missing: true
- rename:
    field: threatintel.malwarebazaar.telfhash
    target_field: threatintel.indicator.file.elf.telfhash
    ignore_missing: true
- append:
    field: related.hash
    value: '{{ threatintel.indicator.file.hash.md5 }}'
    if: ctx?.threatintel?.indicator?.file?.hash?.md5 != null
- append:
    field: related.hash
    value: '{{ threatintel.indicator.file.hash.sha256 }}'
    if: ctx?.threatintel?.indicator?.file?.hash?.sha256 != null
- append:
    field: related.hash
    value: '{{ threatintel.indicator.file.hash.ssdeep }}'
    if: ctx?.threatintel?.indicator?.file?.hash?.ssdeep != null
- append:
    field: related.hash
    value: '{{ threatintel.indicator.file.pe.imphash }}'
    if: ctx?.threatintel?.indicator?.file?.pe?.imphash != null
- append:
    field: related.hash
    value: '{{ threatintel.indicator.file.elf.telfhash }}'
    if: ctx?.threatintel?.indicator?.file?.elf?.telfhash != null
- append:
    field: related.hash
    value: '{{ threatintel.indicator.file.hash.tlsh }}'
    if: ctx?.threatintel?.indicator?.file?.hash?.tlsh != null
- convert:
    field: threatintel.indicator.file.size
    type: long
    ignore_missing: true
- convert:
    field: threatintel.malwarebazaar.intelligence.downloads
    type: long
    ignore_missing: true
- convert:
    field: threatintel.malwarebazaar.intelligence.uploads
    type: long
    ignore_missing: true

######################
# Cleanup processors #
######################
- set:
    field: threatintel.indicator.type
    value: unknown
    if: ctx?.threatintel?.indicator?.type == null
- script:
    lang: painless
    if: ctx?.threatintel != null
    source: |
      void handleMap(Map map) {
        for (def x : map.values()) {
          if (x instanceof Map) {
              handleMap(x);
          } else if (x instanceof List) {
              handleList(x);
          }
        }
      map.values().removeIf(v -> v == null);
      }
      void handleList(List list) {
        for (def x : list) {
            if (x instanceof Map) {
                handleMap(x);
            } else if (x instanceof List) {
                handleList(x);
            }
        }
      }
      handleMap(ctx);
- remove:
    field:
    - threatintel.malwarebazaar.first_seen
    - threatintel.malwarebazaar.last_seen
    - message
    ignore_missing: true
on_failure:
- set:
    field: error.message
    value: '{{ _ingest.on_failure_message }}'
