Coletar registros de IOC do MISP
Este documento explica como ingerir registros de IOC (indicadores de comprometimento) do MISP (Malware Information Sharing Platform) no Google Security Operations usando o Bindplane. O analisador processa os dados nos formatos CSV e JSON. Ele extrai atributos de IOC, como endereços IP, domínios, hashes e URLs, mapeando-os para um modelo de dados unificado (UDM) com detalhes de ameaças, como gravidade, confiança e descrições. O analisador processa entradas de IOC únicas e múltiplas nos dados de entrada, normalizando-as em uma saída UDM consistente.
Antes de começar
Verifique se você tem os pré-requisitos a seguir:
- Uma instância do Google SecOps.
- Um host Linux com
systemd
. - Se você estiver executando um proxy, verifique se as portas do firewall estão abertas de acordo com os requisitos do agente do Bindplane.
- Acesso privilegiado ao seu servidor MISP.
Receber o arquivo de autenticação de ingestão do Google SecOps
- Faça login no console do Google SecOps.
- Acesse Configurações do SIEM > Agentes de coleta.
- Baixe o arquivo de autenticação de ingestão.
- Salve o arquivo de forma segura no sistema em que o Bindplane será instalado.
Receber o ID do cliente do Google SecOps
- Faça login no console do Google SecOps.
- Acesse Configurações do SIEM*> Perfil.
- Copie e salve o ID do cliente na seção Detalhes da organização.
Receber credenciais da API MISP
- Faça login na interface da Web do MISP como administrador.
- Acesse Administração > Listar chaves de autenticação.
- Clique em Adicionar chave de autenticação.
- Informe os seguintes detalhes de configuração:
- Usuário: selecione a conta de usuário associada à chave.
- Opcional: IPs permitidos: especifique os endereços IP permitidos para a chave.
- Validade: deixe em branco se não quiser definir uma data de validade ou defina conforme necessário.
- Clique em Enviar.
- Copie e salve a chave de API em um local seguro.
- Clique em Anotei minha chave.
Configurar a exportação de dados do MISP
Instale o PyMISP no seu servidor MISP:
pip3 install pymisp
Crie o diretório de exportação:
sudo mkdir -p /opt/misp/scripts sudo mkdir -p /opt/misp/ioc_export
Crie o arquivo de credenciais
/opt/misp/scripts/keys.py
:misp_url = 'https://<MISP_SERVER_URL>' misp_key = '<MISP_API_KEY>' misp_verifycert = True misp_client_cert = ''
- Substitua
<MISP_SERVER_URL>
pelo URL do servidor MISP. - Substitua
<MISP_API_KEY>
pela chave de API dos pré-requisitos.
- Substitua
Crie o script de exportação
/opt/misp/scripts/misp_export.py
:#!/usr/bin/env python3 # -*- coding: utf-8 -*- import argparse from pymisp import ExpandedPyMISP from keys import misp_url, misp_key, misp_verifycert if __name__ == '__main__': parser = argparse.ArgumentParser(description='Export MISP IOCs to CSV format.') parser.add_argument("--controller", default='attributes', help="Controller to use for search (events, objects, attributes)") parser.add_argument("--event_id", help="Event ID to fetch. Without it, fetches recent data.") parser.add_argument("--attributes", nargs='*', help="Requested attributes for CSV export") parser.add_argument("--misp_types", nargs='+', help="MISP types to fetch (ip-src, hostname, domain, etc.)") parser.add_argument("--context", action='store_true', help="Add event level context (tags, metadata)") parser.add_argument("--outfile", required=True, help="Output file to write the CSV data") parser.add_argument("--last", required=True, help="Time period: days (d), hours (h), minutes (m) - e.g., 1d, 12h, 30m") args = parser.parse_args() api = ExpandedPyMISP(misp_url, misp_key, misp_verifycert, debug=False) response = api.search( controller=args.controller, return_format='csv', type_attribute=args.misp_types, publish_timestamp=args.last, include_context=args.context, requested_attributes=args.attributes or None ) with open(args.outfile, 'w') as response_file: response_file.write(response)
- Torne o script executável:
sudo chmod +x /opt/misp/scripts/misp_export.py
Programar exportações de dados do MISP
- Crie exportações programadas usando crontab:
sudo crontab -e
Adicione as seguintes entradas de cron:
# Export different IOC types daily with context 0 0 * * * python3 /opt/misp/scripts/misp_export.py --outfile /opt/misp/ioc_export/domains.csv --misp_types domain --last 1d --context --attributes uuid event_id category type value comment to_ids date attribute_tag event_info 0 1 * * * python3 /opt/misp/scripts/misp_export.py --outfile /opt/misp/ioc_export/ip-src.csv --misp_types ip-src --last 1d --context --attributes uuid event_id category type value comment to_ids date attribute_tag event_info 0 2 * * * python3 /opt/misp/scripts/misp_export.py --outfile /opt/misp/ioc_export/ip-dst.csv --misp_types ip-dst --last 1d --context --attributes uuid event_id category type value comment to_ids date attribute_tag event_info 0 3 * * * python3 /opt/misp/scripts/misp_export.py --outfile /opt/misp/ioc_export/urls.csv --misp_types url --last 1d --context --attributes uuid event_id category type value comment to_ids date attribute_tag event_info 0 4 * * * python3 /opt/misp/scripts/misp_export.py --outfile /opt/misp/ioc_export/sha256.csv --misp_types sha256 --last 1d --context --attributes uuid event_id category type value comment to_ids date attribute_tag event_info 0 5 * * * python3 /opt/misp/scripts/misp_export.py --outfile /opt/misp/ioc_export/filenames.csv --misp_types filename --last 1d --context --attributes uuid event_id category type value comment to_ids date attribute_tag event_info 0 6 * * * python3 /opt/misp/scripts/misp_export.py --outfile /opt/misp/ioc_export/registries.csv --misp_types regkey --last 1d --context --attributes uuid event_id category type value comment to_ids date attribute_tag event_info 0 7 * * * python3 /opt/misp/scripts/misp_export.py --outfile /opt/misp/ioc_export/mutexes.csv --misp_types mutex --last 1d --context --attributes uuid event_id category type value comment to_ids date attribute_tag event_info
Se quiser, programe uma extração de feeds do MISP:
23 0 * * * curl --insecure --header "Authorization: <MISP_API_KEY>" --header "Accept: application/json" --header "Content-Type: application/json" https://<MISP_SERVER_URL>/feeds/fetchFromAllFeeds
Instalar o agente do Bindplane
Instale o agente do Bindplane no sistema operacional Linux de acordo com as instruções a seguir.
Instalação do Linux
- Abra um terminal com privilégios de root ou sudo.
Execute este comando:
sudo sh -c "$(curl -fsSlL https://github.com/observiq/bindplane-otel-collector/releases/latest/download/install_unix.sh)" install_unix.sh
Outros recursos de instalação
- Para mais opções de instalação, consulte o guia de instalação.
Configurar o agente do Bindplane para ingerir registros do MISP e enviar ao Google SecOps
Acesse o arquivo de configuração:
- Localize o arquivo
config.yaml
. Normalmente, ele fica no diretório/etc/bindplane-agent/
no Linux. - Abra o arquivo usando um editor de texto (por exemplo,
nano
,vi
).
- Localize o arquivo
Edite o arquivo
config.yaml
da seguinte forma:receivers: filelog: file_path: /opt/misp/ioc_export/*.log exporters: chronicle/chronicle_w_labels: compression: gzip # Adjust the path to the credentials file you downloaded in Step 1 creds_file_path: '/path/to/ingestion-authentication-file.json' # Replace with your actual customer ID from Step 2 customer_id: <customer_id> endpoint: malachiteingestion-pa.googleapis.com # Add optional ingestion labels for better organization ingestion_labels: log_type: 'MISP_IOC' raw_log_field: body service: pipelines: logs/source0__chronicle_w_labels-0: receivers: - filelog exporters: - chronicle/chronicle_w_labels
- Substitua
<CUSTOMER_ID>
pelo ID de cliente real dos pré-requisitos. - Atualize
/path/to/ingestion-authentication-file.json
para o caminho em que o arquivo de autenticação foi salvo.
- Substitua
Reinicie o agente do Bindplane para aplicar as mudanças
Para reiniciar o agente do Bindplane em Linux, execute o seguinte comando:
sudo systemctl restart observiq-otel-collector
Tabela de mapeamento do UDM
Campo de registro | Mapeamento do UDM | Lógica |
---|---|---|
Attribute.category | entity.metadata.threat.category_details | Mapeamento direto do campo category no objeto Attribute . |
Attribute.comment | entity.metadata.threat.summary | Mapeamento direto do campo comment no objeto Attribute . |
Attribute.deleted | entity.metadata.threat.detection_fields.value | Mapeamento direto do campo deleted no objeto Attribute . A chave está definida como Attribute deleted . |
Attribute.event_id | entity.metadata.threat.detection_fields.value | Mapeamento direto do campo event_id no objeto Attribute . A chave está definida como Attribute event_id . |
Attribute.first_seen | entity.metadata.threat.detection_fields.value | Mapeamento direto do campo first_seen no objeto Attribute . A chave está definida como Attribute first_seen . |
Attribute.id | entity.metadata.threat.detection_fields.value | Mapeamento direto do campo id no objeto Attribute . A chave é definida como Attribute id ou Attribute id $$ , dependendo do formato do registro bruto. |
Attribute.timestamp | entity.metadata.threat.detection_fields.value | Mapeamento direto do campo timestamp no objeto Attribute . A chave está definida como Attribute timestamp . |
Attribute.to_ids | entity.metadata.threat.detection_fields.value | Mapeamento direto do campo to_ids no objeto Attribute . A chave está definida como Attribute to_ids . |
Attribute.type | entity.metadata.threat.category_details | Mapeamento direto do campo type no objeto Attribute . |
Attribute.type | log_type | Usado para determinar o tipo de IOC e mapeá-lo para os campos de UDM adequados. |
Attribute.uuid | entity.metadata.product_entity_id | Mapeamento direto do campo uuid no objeto Attribute . |
Attribute.value | entity.entity.file.full_path | Mapeado se o Attribute.type for filename . |
Attribute.value | entity.entity.file.md5 | Mapeado se o Attribute.type for md5 . |
Attribute.value | entity.entity.file.sha1 | Mapeado se o Attribute.type for sha1 . |
Attribute.value | entity.entity.file.sha256 | Mapeado se o Attribute.type for sha256 . |
Attribute.value | entity.entity.hostname | Mapeado se o Attribute.type for domain . |
Attribute.value | entity.entity.ip | Mapeado se o Attribute.type for ip-dst , ip-dst|port ou ip-src . O valor é extraído usando um padrão grok. |
Attribute.value | entity.entity.resource.name | Mapeado se o Attribute.type for mutex . |
Attribute.value | entity.entity.registry.registry_key | Mapeado se o Attribute.type for regkey . |
Attribute.value | entity.entity.url | Mapeado se o Attribute.type for uri ou URL . |
column1 | entity.metadata.product_entity_id | Mapeamento direto da primeira coluna nos dados CSV. |
column14 | event_info | Usado para anexar mais informações ao campo threat_sr.description . |
column16 | event_source_org | Mapeamento direto da 16ª coluna nos dados CSV. |
column18 | threat_level | Mapeamento direto da 18ª coluna nos dados CSV. |
column21 | descrição | Mapeamento direto da 21ª coluna nos dados CSV. |
column3 | misp_category | Mapeamento direto da terceira coluna nos dados CSV. |
column4 | tipo | Mapeamento direto da quarta coluna nos dados CSV. |
column5 | valor | Mapeamento direto da quinta coluna nos dados CSV. |
column6 | comentário | Mapeamento direto da sexta coluna nos dados CSV. |
column8 | ts1 | Mapeamento direto da oitava coluna nos dados CSV. |
descrição | ioc.description | O valor é gerado combinando os campos description e event_info , separados por - additional info: . |
descrição | entity.metadata.threat.description | Mapeamento direto do campo description . |
event_creator_email | entity.entity.labels.value | Mapeamento direto do campo event_creator_email . A chave está definida como event_creator_email . |
event_source_org | ioc.feed_name | Mapeamento direto do campo event_source_org . |
event_source_org | entity.metadata.threat.threat_feed_name | Mapeamento direto do campo event_source_org . |
Feed.publish | entity.metadata.threat.detection_fields.value | Mapeamento direto do campo publish no objeto Feed . A chave está definida como Feed publish . |
first_seen | ioc.active_timerange.start | Mapeamento direto do campo first_seen . O valor é analisado como uma data. |
first_seen | entity.metadata.interval.start_time | Mapeamento direto do campo first_seen . O valor é analisado como uma data. |
informações | entity.metadata.description | Mapeamento direto do campo info . |
last_seen | ioc.active_timerange.end | Mapeamento direto do campo last_seen . O valor é analisado como uma data. |
log.category | ioc.categorization | Mapeamento direto do campo category no objeto log . |
log.category | entity.metadata.threat.category_details | Mapeamento direto do campo category no objeto log . |
log.comment | entity.entity.file.full_path | Mapeado se log.type for filename e o campo comment não for Artifacts dropped . |
log.comment | entity.metadata.threat.detection_fields.value | Mapeamento direto do campo comment no objeto log . A chave está definida como Attribute comment . |
log.comment | entity.metadata.threat.summary | Mapeamento direto do campo comment no objeto log . |
log.deleted | entity.metadata.threat.detection_fields.value | Mapeamento direto do campo deleted no objeto log . A chave está definida como Attribute deleted . |
log.event_id | entity.metadata.threat.detection_fields.value | Mapeamento direto do campo event_id no objeto log . A chave está definida como Attribute event_id . |
log.first_seen | entity.metadata.threat.detection_fields.value | Mapeamento direto do campo first_seen no objeto log . A chave está definida como Attribute first_seen . |
log.id | entity.metadata.threat.detection_fields.value | Mapeamento direto do campo id no objeto log . A chave está definida como Attribute id . |
log.timestamp | entity.metadata.threat.detection_fields.value | Mapeamento direto do campo timestamp no objeto log . A chave está definida como Attribute timestamp . |
log.to_ids | entity.metadata.threat.detection_fields.value | Mapeamento direto do campo to_ids no objeto log . A chave está definida como Attribute to_ids . |
log.type | ioc.categorization | Mapeamento direto do campo type no objeto log . |
log.type | log_type | Usado para determinar o tipo de IOC e mapeá-lo para os campos de UDM adequados. |
log.uuid | entity.metadata.product_entity_id | Mapeamento direto do campo uuid no objeto log . |
log.value | entity.entity.file.full_path | Mapeado se o log.type for filename . |
log.value | entity.entity.file.md5 | Mapeado se o log.type for md5 . |
log.value | entity.entity.file.sha1 | Mapeado se o log.type for sha1 . |
log.value | entity.entity.file.sha256 | Mapeado se o log.type for sha256 . |
log.value | entity.entity.hostname | Mapeado se o log.type for domain . |
log.value | entity.entity.ip | Mapeado se o log.type for ip-dst , ip-dst|port ou ip-src . O valor é extraído usando um padrão grok. |
log.value | entity.entity.resource.name | Mapeado se o log.type for mutex . |
log.value | entity.entity.registry.registry_key | Mapeado se o log.type for regkey . |
log.value | entity.entity.url | Mapeado se o log.type for uri ou url . |
log.value | ioc.domain_and_ports.domain | Mapeado se o log.type for domain . |
log.value | entity.entity.user.email_addresses | Mapeado se o log.type for threat-actor . |
misp_category | entity.metadata.threat.category_details | Mapeamento direto do campo misp_category . |
Org.name | entity.metadata.threat.detection_fields.value | Mapeamento direto do campo name no objeto Org . A chave está definida como Org name . |
publicado | entity.metadata.threat.detection_fields.value | Mapeamento direto do campo published . A chave está definida como published . |
Tag.colour | entity.metadata.threat.detection_fields.value | Mapeamento direto do campo colour no objeto Tag . A chave está definida como tag colour . |
Tag.exportable | entity.metadata.threat.detection_fields.value | Mapeamento direto do campo exportable no objeto Tag . A chave está definida como tag exportable . |
Tag.hide_tag | entity.metadata.threat.detection_fields.value | Mapeamento direto do campo hide_tag no objeto Tag . A chave está definida como tag hide_tag . |
Tag.id | entity.metadata.threat.detection_fields.value | Mapeamento direto do campo id no objeto Tag . A chave está definida como tag id . |
Tag.is_custom_galaxy | entity.metadata.threat.detection_fields.value | Mapeamento direto do campo is_custom_galaxy no objeto Tag . A chave está definida como tag is_custom_galaxy . |
Tag.is_galaxy | entity.metadata.threat.detection_fields.value | Mapeamento direto do campo is_galaxy no objeto Tag . A chave está definida como tag is_galaxy . |
Tag.isinherited | entity.metadata.threat.detection_fields.value | Mapeamento direto do campo isinherited no objeto Tag . A chave está definida como tag isinherited . |
Tag.name | entity.metadata.threat.detection_fields.value | Mapeamento direto do campo name no objeto Tag . A chave está definida como tag name . |
Tag.numerical_value | entity.metadata.threat.detection_fields.value | Mapeamento direto do campo numerical_value no objeto Tag . A chave está definida como tag numerical_value . |
Tag.user_id | entity.metadata.threat.detection_fields.value | Mapeamento direto do campo user_id no objeto Tag . A chave está definida como tag user_id . |
threat_level | ioc.raw_severity | Mapeamento direto do campo threat_level . |
threat_level | entity.metadata.threat.severity_details | Mapeamento direto do campo threat_level . |
threat_level_id | entity.entity.labels.value | Mapeamento direto do campo threat_level_id . A chave está definida como threat_level_id . |
ts1 | ioc.active_timerange.start | Mapeamento direto do campo ts1 . O valor é analisado como uma data. |
ts1 | entity.metadata.interval.start_time | Mapeamento direto do campo ts1 . O valor é analisado como uma data. |
entity.entity.file.full_path | Mapeado se o type for filename . |
|
entity.entity.file.md5 | Mapeado se o type for md5 . |
|
entity.entity.file.sha1 | Mapeado se o type for sha1 . |
|
entity.entity.file.sha256 | Mapeado se o type for sha256 . |
|
entity.entity.hostname | Mapeado se o type for domain . |
|
entity.entity.ip | Mapeado se o type for ip-dst , ip-dst|port ou ip-src . O valor é extraído usando um padrão grok. |
|
entity.entity.port | Mapeado se o campo port não estiver vazio. O valor é convertido em um número inteiro. |
|
entity.entity.resource.name | Mapeado se o type for mutex . |
|
entity.entity.resource.resource_subtype | Mapeado se o type for regkey . O valor é definido como regkey . |
|
entity.entity.resource.resource_type | Mapeado se o type for mutex ou regkey . O valor é definido como MUTEX ou STORAGE_OBJECT , respectivamente. |
|
entity.entity.registry.registry_key | Mapeado se o type for regkey . |
|
entity.entity.url | Mapeado se o type for uri ou url . |
|
entity.metadata.collected_timestamp | O valor é definido como o carimbo de data/hora da entrada de registro bruta. | |
entity.metadata.description | O valor é definido como o campo type se o registro bruto estiver no formato CSV. Caso contrário, ele será definido como o campo info . |
|
entity.metadata.entity_type | O valor é determinado com base no campo type ou log_type . Pode ser DOMAIN_NAME , FILE , IP_ADDRESS , MUTEX , RESOURCE ou URL . |
|
entity.metadata.interval.end_time | O valor é definido como um padrão de 253402300799 segundos. | |
entity.metadata.interval.start_time | O valor é definido como o campo first_seen se não estiver vazio. Caso contrário, ele será definido como um valor padrão de 1 segundo ou o carimbo de data/hora da entrada de registro bruta. |
|
entity.metadata.product_name | O valor é definido como MISP . |
|
entity.metadata.threat.confidence | O valor é definido como UNKNOWN_CONFIDENCE se o campo confidence estiver vazio ou for f . Caso contrário, ele será definido como HIGH_CONFIDENCE , MEDIUM_CONFIDENCE ou LOW_CONFIDENCE com base no valor do campo confidence . |
|
entity.metadata.threat.confidence_details | Mapeamento direto do campo confidence . |
|
entity.metadata.threat.detection_fields | O valor é uma lista de pares de chave-valor extraídos de vários campos no registro bruto. | |
entity.metadata.vendor_name | O valor é definido como MISP . |
|
ioc.active_timerange.end | O valor é definido como o campo last_seen se não estiver vazio. |
|
ioc.active_timerange.start | O valor é definido como o campo ts1 ou first_seen se eles não estiverem vazios. Caso contrário, ele será definido como um valor padrão de 1 segundo. |
|
ioc.categorization | O valor é definido como misp_category IOCs se o registro bruto estiver no formato CSV. Caso contrário, ele será definido como o campo category no objeto Attribute ou log . |
|
ioc.confidence_score | Mapeamento direto do campo confidence . |
|
ioc.description | O valor é gerado combinando os campos description e event_info , separados por - additional info: . |
|
ioc.domain_and_ports.domain | Mapeado se o type ou log_type for domain . |
|
ioc.feed_name | O valor é definido como MISP se o campo event_source_org estiver vazio. Caso contrário, ele será definido como o campo event_source_org . |
|
ioc.ip_and_ports.ip_address | Mapeado se o campo ip não estiver vazio. O valor é convertido em um endereço IP. |
|
ioc.ip_and_ports.ports | Mapeado se o campo port não estiver vazio. O valor é convertido em um número inteiro sem sinal. |
|
ioc.raw_severity | Mapeamento direto do campo threat_level . |
|
timestamp | O valor é definido como o carimbo de data/hora da entrada de registro bruta. |
Precisa de mais ajuda? Receba respostas de membros da comunidade e profissionais do Google SecOps.