Recolha registos de IOCs do MISP
Este documento explica como carregar registos de IOCs (Indicadores de comprometimento) da MISP (Malware Information Sharing Platform) para o Google Security Operations através do Bindplane. O analisador processa os dados nos formatos CSV e JSON. Extrai atributos de IOCs, como endereços IP, domínios, hashes e URLs, mapeando-os para um modelo de dados unificado (UDM) juntamente com detalhes de ameaças, como gravidade, confiança e descrições. O analisador processa entradas de IOCs únicas e múltiplas nos dados de entrada, normalizando-as numa saída de UDM consistente.
Antes de começar
Certifique-se de que tem os seguintes pré-requisitos:
- Uma instância do Google SecOps.
- Um anfitrião Linux com
systemd
. - Se estiver a ser executado através de um proxy, certifique-se de que as portas da firewall estão abertas de acordo com os requisitos do agente Bindplane.
- Acesso privilegiado ao seu servidor MISP.
Obtenha o ficheiro de autenticação de carregamento do Google SecOps
- Inicie sessão na consola Google SecOps.
- Aceda a Definições do SIEM > Agentes de recolha.
- Transfira o ficheiro de autenticação de carregamento.
- Guarde o ficheiro de forma segura no sistema onde o Bindplane vai ser instalado.
Obtenha o ID de cliente do Google SecOps
- Inicie sessão na consola Google SecOps.
- Aceda a Definições do SIEM*> Perfil.
- Copie e guarde o ID do cliente da secção Detalhes da organização.
Obtenha credenciais da API MISP
- Inicie sessão na interface Web do MISP como administrador.
- Aceda a Administração > Listar chaves de autorização.
- Clique em Adicionar chave de autenticação.
- Indique os seguintes detalhes de configuração:
- Utilizador: selecione a conta de utilizador associada à chave.
- Opcional: IPs permitidos: especifique os endereços IP permitidos para a chave.
- Validade: deixe vazio para não ter validade ou defina conforme necessário.
- Clique em Enviar.
- Copie e guarde a chave da API num local seguro.
- Clique em Tomei nota da minha chave.
Configure 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 ficheiro 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 seu servidor MISP. - Substitua
<MISP_API_KEY>
pela chave 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
Agende exportações de dados do MISP
- Crie exportações agendadas com o crontab:
sudo crontab -e
Adicione as seguintes entradas 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
Opcionalmente, agende uma obtenção de feeds a partir 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
Instale o agente do Bindplane
Instale o agente Bindplane no seu sistema operativo Linux de acordo com as seguintes instruções.
Instalação do Linux
- Abra um terminal com privilégios de raiz ou sudo.
Execute o seguinte comando:
sudo sh -c "$(curl -fsSlL https://github.com/observiq/bindplane-otel-collector/releases/latest/download/install_unix.sh)" install_unix.sh
Recursos de instalação adicionais
- Para ver opções de instalação adicionais, consulte o guia de instalação.
Configure o agente Bindplane para carregar registos MISP e enviá-los para o Google SecOps
Aceda ao ficheiro de configuração:
- Localize o ficheiro
config.yaml
. Normalmente, encontra-se no diretório/etc/bindplane-agent/
no Linux. - Abra o ficheiro com um editor de texto (por exemplo,
nano
ouvi
).
- Localize o ficheiro
Edite o ficheiro
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 seu ID de cliente real dos pré-requisitos. - Atualize
/path/to/ingestion-authentication-file.json
para o caminho onde o ficheiro de autenticação foi guardado.
- Substitua
Reinicie o agente do Bindplane para aplicar as alterações
Para reiniciar o agente do Bindplane no Linux, execute o seguinte comando:
sudo systemctl restart observiq-otel-collector
Tabela de mapeamento do UDM
Campo de registo | 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 tecla está definida como Attribute deleted . |
Attribute.event_id | entity.metadata.threat.detection_fields.value | Mapeamento direto do campo event_id no objeto Attribute . A tecla 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 tecla está definida como Attribute first_seen . |
Attribute.id | entity.metadata.threat.detection_fields.value | Mapeamento direto do campo id no objeto Attribute . A chave está definida como Attribute id ou Attribute id $$ , consoante o formato do registo não processado. |
Attribute.timestamp | entity.metadata.threat.detection_fields.value | Mapeamento direto do campo timestamp no objeto Attribute . A tecla está definida como Attribute timestamp . |
Attribute.to_ids | entity.metadata.threat.detection_fields.value | Mapeamento direto do campo to_ids no objeto Attribute . A tecla 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 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 através de 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 elemento Attribute.type for uri ou URL . |
coluna1 | entity.metadata.product_entity_id | Mapeamento direto a partir da primeira coluna nos dados CSV. |
column14 | event_info | Usado para anexar informações adicionais 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. |
coluna3 | misp_category | Mapeamento direto a partir da terceira coluna nos dados CSV. |
column4 | escrever | Mapeamento direto da quarta coluna nos dados CSV. |
column5 | valor | Mapeamento direto a partir da quinta coluna nos dados CSV. |
column6 | comentário | Mapeamento direto a partir da sexta coluna nos dados CSV. |
column8 | ts1 | Mapeamento direto a partir da oitava coluna nos dados CSV. |
descrição | ioc.description | O valor é gerado combinando o campo description com o campo 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 tecla 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 tecla 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ção | 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 o campo 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 tecla 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 tecla está definida como Attribute deleted . |
log.event_id | entity.metadata.threat.detection_fields.value | Mapeamento direto do campo event_id no objeto log . A tecla 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 tecla está definida como Attribute first_seen . |
log.id | entity.metadata.threat.detection_fields.value | Mapeamento direto do campo id no objeto log . A tecla está definida como Attribute id . |
log.timestamp | entity.metadata.threat.detection_fields.value | Mapeamento direto do campo timestamp no objeto log . A tecla está definida como Attribute timestamp . |
log.to_ids | entity.metadata.threat.detection_fields.value | Mapeamento direto do campo to_ids no objeto log . A tecla 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 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 através de 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 elemento 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 tecla está definida como Org name . |
publicados | entity.metadata.threat.detection_fields.value | Mapeamento direto do campo published . A tecla está definida como published . |
Tag.colour | entity.metadata.threat.detection_fields.value | Mapeamento direto do campo colour no objeto Tag . A tecla está definida como tag colour . |
Tag.exportable | entity.metadata.threat.detection_fields.value | Mapeamento direto do campo exportable no objeto Tag . A tecla está definida como tag exportable . |
Tag.hide_tag | entity.metadata.threat.detection_fields.value | Mapeamento direto do campo hide_tag no objeto Tag . A tecla está definida como tag hide_tag . |
Tag.id | entity.metadata.threat.detection_fields.value | Mapeamento direto do campo id no objeto Tag . A tecla 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 tecla 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 tecla está definida como tag is_galaxy . |
Tag.isinherited | entity.metadata.threat.detection_fields.value | Mapeamento direto do campo isinherited no objeto Tag . A tecla está definida como tag isinherited . |
Tag.name | entity.metadata.threat.detection_fields.value | Mapeamento direto do campo name no objeto Tag . A tecla está definida como tag name . |
Tag.numerical_value | entity.metadata.threat.detection_fields.value | Mapeamento direto do campo numerical_value no objeto Tag . A tecla 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 tecla 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 tecla 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 através de um padrão grok. |
|
entity.entity.port | Mapeado se o campo port não estiver vazio. O valor é convertido num 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 elemento type for mutex ou regkey . O valor é definido como MUTEX ou STORAGE_OBJECT , respetivamente. |
|
entity.entity.registry.registry_key | Mapeado se o type for regkey . |
|
entity.entity.url | Mapeado se o elemento type for uri ou url . |
|
entity.metadata.collected_timestamp | O valor é definido como a data/hora da entrada do registo não processado. | |
entity.metadata.description | O valor é definido como o campo type se o registo não processado estiver no formato CSV. Caso contrário, é definido para 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 está definido para um valor predefinido de 253402300799 segundos. | |
entity.metadata.interval.start_time | O valor é definido para o campo first_seen se não estiver vazio. Caso contrário, é definido como um valor predefinido de 1 segundo ou a data/hora da entrada do registo não processado. |
|
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, é 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 registo não processado. | |
entity.metadata.vendor_name | O valor é definido como MISP . |
|
ioc.active_timerange.end | O valor é definido para o campo last_seen se não estiver vazio. |
|
ioc.active_timerange.start | O valor é definido como o campo ts1 ou first_seen , se não estiverem vazios. Caso contrário, é definido um valor predefinido de 1 segundo. |
|
ioc.categorization | O valor é definido como misp_category IOCs se o registo não processado estiver no formato CSV. Caso contrário, é definido para o campo category no objeto Attribute ou log . |
|
ioc.confidence_score | Mapeamento direto do campo confidence . |
|
ioc.description | O valor é gerado combinando o campo description com o campo event_info , separados por - additional info: . |
|
ioc.domain_and_ports.domain | Mapeado se o elemento 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, é definido para o campo event_source_org . |
|
ioc.ip_and_ports.ip_address | Mapeado se o campo ip não estiver vazio. O valor é convertido num endereço IP. |
|
ioc.ip_and_ports.ports | Mapeado se o campo port não estiver vazio. O valor é convertido num número inteiro sem sinal. |
|
ioc.raw_severity | Mapeamento direto do campo threat_level . |
|
timestamp | O valor é definido como a data/hora da entrada do registo não processado. |
Precisa de mais ajuda? Receba respostas de membros da comunidade e profissionais da Google SecOps.