
Extrator de Indicador de Comprometimento (IOC) Desarmado.
Indicador de Comprometimento (IOC) extrator para alguns dos artefatos mais comumente ingeridos.
O pacote iocextract é uma biblioteca e interface de linha de comando (CLI) para extrair URLs, endereços IP, hashes MD5/SHA, endereços de e-mail e regras YARA de corpora de texto. Permite extrair IOCs codificados e "desarmados" (defanged) e opcionalmente decodificá-los ou rearmá-los (refang).
É prática comum entre analistas de malware ou softwares de endpoint "desarmar" IOCs como URLs e endereços IP, a fim de evitar exposição acidental a conteúdo malicioso ativo. Ser capaz de extrair e agregar esses IOCs é frequentemente valioso para analistas. Infelizmente, as ferramentas existentes de "extração de IOC" muitas vezes passam por eles, pois não são capturadas por regex padrão.
Por exemplo, a técnica simples de desarme de cercar períodos com colchetes:
127[.]0[.]0[.]1
Ferramentas existentes que usam um regex simples de endereço IP ignorarão completamente este IOC.
Combinando regex especialmente elaborado com algum pós-processamento personalizado, somos capazes tanto de detectar quanto de desobfuscar IOCs "desarmados". Isso economiza tempo e esforço para o analista, que de outra forma teria que encontrar e converter manualmente IOCs em formato legível por máquina.
Muitos usuários do Twitter postam C2s ou outras informações valiosas de IOC com URLs desarmadas. Por exemplo, este tweet de @InQuest:
Leitura recomendada e ótimo trabalho de @unit42_intel:
https://researchcenter.paloaltonetworks.com/2018/02/unit42-sofacy-attacks-multiple-government-entities/ ...
Os clientes da InQuest têm detecção para ameaças entregues de hotfixmsupload[.]com
desde 6/3/2017 e cdnverify[.]net desde 1/2/18.
Se executarmos isso através do extrator, podemos facilmente extrair as URLs:
https://researchcenter.paloaltonetworks.com/2018/02/unit42-sofacy-attacks-multiple-government-entities/
hotfixmsupload[.]com
cdnverify[.]net
Passar refang=True no momento da extração removeria a ofuscação, mas como estes são IOCs reais, vamos mantê-los desarmados em nossa documentação.
Você pode precisar instalar os cabeçalhos de desenvolvimento do Python para instalar a dependência regex. Em sistemas baseados em Ubuntu/Debian, tente:
sudo apt-get install python-dev
Em seguida, instale o iocextract via pip:
pip install iocextract
Se tiver problemas para instalar no Windows, tente instalar o regex diretamente baixando a wheel apropriada do PyPI e instalando via pip:
pip install regex-2018.06.21-cp27-none-win_amd64.whl
Tente extrair algumas URLs desarmadas:
import iocextract
content = \
"""
Eu realmente adoro example[.]com!
Todos os bots estão em hxxp://example.com/bad/url atualmente.
C2: tcp://example[.]com:8989/bad
"""
for url in iocextract.extract_urls(content):
print(url)
# Saída
# hxxp://example.com/bad/url
# tcp://example[.]com:8989/bad
# example[.]com
# tcp://example[.]com:8989/bad
NOTA: Algumas URLs podem aparecer duas vezes se forem capturadas por vários regexes.
Se você quiser, também pode "rearmar" ou remover métodos comuns de ofuscação dos IOCs:
import iocextract
for url in iocextract.extract_urls(content, refang=True):
print(url)
# Saída
# http://example.com/bad/url
# http://example.com:8989/bad
# http://example.com
# http://example.com:8989/bad
Se você não quiser desarmar os IOCs extraídos durante a extração, também pode desabilitar isso:
import iocextract
content = \
"""
http://example.com/bad/url
http://example.com:8989/bad
http://example.com
http://example.com:8989/bad
"""
for url in iocextract.extract_urls(content, defang=False):
print(url)
# Saída
# http://example.com/bad/url
# http://example.com:8989/bad
# http://example.com
# http://example.com:8989/bad
Todas as funções extract_* nesta biblioteca retornam iteradores, não listas. O benefício desse comportamento é que o iocextract pode processar entradas extremamente grandes, com uma sobrecarga muito baixa. No entanto, se por algum motivo você precisar iterar sobre os IOCs mais de uma vez, terá que salvar os resultados como uma lista:
import iocextract
content = \
"""
Eu realmente adoro example[.]com!
Todos os bots estão em hxxp://example.com/bad/url atualmente.
C2: tcp://example[.]com:8989/bad
"""
print(list(iocextract.extract_urls(content)))
# ['hxxp://example.com/bad/url', 'tcp://example[.]com:8989/bad', 'example[.]com', 'tcp://example[.]com:8989/bad']
Uma ferramenta de linha de comando também está incluída:
$ iocextract -h
usage: iocextract [-h] [--input INPUT] [--output OUTPUT] [--extract-emails]
[--extract-ips] [--extract-ipv4s] [--extract-ipv6s]
[--extract-urls] [--extract-yara-rules] [--extract-hashes]
[--custom-regex REGEX_FILE] [--refang] [--strip-urls]
[--wide]
Extrator Avançado de Indicadores de Comprometimento (IOC). Se nenhum argumento for
especificado, o comportamento padrão é extrair todos os IOCs.
argumentos opcionais:
-h, --help mostra esta mensagem de ajuda e sai
--input INPUT padrão: stdin
--output OUTPUT padrão: stdout
--extract-emails
--extract-ips
--extract-ipv4s
--extract-ipv6s
--extract-urls
--extract-yara-rules
--extract-hashes
--custom-regex REGEX_FILE arquivo com strings regex personalizadas, uma por linha, com um grupo de captura cada
--refang padrão: não
--strip-urls remove possível lixo do final das URLs. padrão: não
--wide pré-processa a entrada para permitir correspondências de caracteres codificados em wide. padrão: não
NOTA: Apenas URLs, e-mails e endereços IPv4 podem ser "rearmados".
Você está...
P. Extraindo IOCs possivelmente desarmados de texto simples, como o conteúdo de tweets ou postagens de blog?
R. Sim! É exatamente para isso que o iocextract foi projetado e onde ele tem melhor desempenho. Quer ir mais longe e automatizar a extração e armazenamento? Confira o ThreatIngestor.
P. Extraindo URLs que foram codificadas em hex ou base64?
R. Sim, mas a CLI pode não fornecer os melhores resultados. Tente escrever um script Python e chamar
iocextract.extract_encoded_urlsdiretamente.
Nota: Você provavelmente terá lixo extra no final das URLs.
P. Extraindo IOCs que não foram desarmados, de HTML/XML/RTF?
R. Talvez, mas você deve considerar usar a flag
--strip-urlsda CLI (ou o parâmetrostrip=Truena biblioteca), e ainda assim pode obter algum lixo extra na saída. Se estiver extraindo de HTML, considere usar algo como Beautiful Soup para primeiro isolar o conteúdo do texto e depois passar para o iocextract, como neste exemplo.
P. Extraindo IOCs que não foram desarmados, de dados binários como executáveis, ou entradas muito grandes?
R. Existe uma versão muito simplista disso disponível ao usar como biblioteca, mas requer o parâmetro
defang=Falsee pode potencialmente perder alguns IOCs. O regex no iocextract foi projetado para ser flexível para capturar IOCs desarmados. Se você não conseguir coletar as informações necessárias, considere usar algo como Cacador.
Esta biblioteca atualmente suporta os seguintes IOCs:
[.], mesmo sem especificador de protocolo@ ou atPara endereços IPv4, as seguintes técnicas de desarme são suportadas:
Para endereços de e-mail, as seguintes técnicas de desarme são suportadas:
Para URLs, as seguintes técnicas de desarme são suportadas:
NOTA: As tabelas acima não são exaustivas, e outros padrões de URL/desarme também podem ser extraídos corretamente. Se você notar algo faltando ou não funcionando corretamente, sinta-se à vontade para nos informar através das Issues do GitHub.
O regex base64 foi gerado com a ferramenta regex base64 de @deadpixi.
Se você deseja usar a CLI para extrair IOCs usando seu próprio regex personalizado, crie um arquivo de texto simples com uma string regex por linha e passe-o com a flag --custom-regex. Certifique-se de que cada string regex inclui exatamente um grupo de captura.
Por exemplo:
http://(example\.com)/
(?:https|ftp)://(example\.com)/
Este arquivo regex personalizado extrairá o domínio example.com de URLs correspondentes. O grupo não capturador (?: ) não será incluído nas correspondências.
Se você quiser extrair a correspondência inteira, basta colocar parênteses em torno de toda a string regex, assim:
(https?://.*?.com)
Se seu regex for inválido, você verá uma mensagem de erro como esta:
Error in custom regex: missing ) at position 5
Se seu regex não incluir um grupo de captura, você verá uma mensagem de erro como esta:
Error in custom regex: no such group
Sempre use um único grupo de captura ao trabalhar com regex personalizado. Aqui está um exemplo rápido:
[
r'(my regex)', # Isso produz 'my regex' se o padrão corresponder
r'my (re)gex', # Isso produz 're' se o padrão corresponder
]
Usar mais de um grupo de captura pode causar resultados inesperados. Confira este exemplo:
[
r'my regex', # Isso não produz nada
r'(my) (re)gex', # Isso produz 'my' se o padrão corresponder
]
Por quê? Porque o resultado sempre produzirá apenas a primeira correspondência de grupo de cada regex.
Para consultas regex mais complexas, você pode combinar grupos de captura e não capturadores assim:
[
r'(?:my|your) (re)gex', # Isso produz 're' se o padrão corresponder
]
Agora você pode comparar a sintaxe (?: ) para grupos não capturadores vs a sintaxe ( ) para o grupo de captura.
Se o iocextract não atender ao seu caso de uso, vários projetos similares existem. Confira as tags defang e indicators-of-compromise no GitHub, bem como:
Se você deseja automatizar extração, enriquecimento, exportação e mais de IOCs, confira o ThreatIngestor.
Se você está trabalhando com regras YARA, pode se interessar pelo plyara.
Se você tem uma técnica de desarme que não passa pelo extrator, ou se encontrar algum bug, Pull Requests e Issues são sempre bem-vindos. A biblioteca é lançada sob uma licença GPL-2.0 license.
Você está usando? Quer ver seu site listado aqui? Nos avise!
| Técnica | Desarmado | Rearmado |
|---|
. -> [.] | 1[.]1[.]1[.]1 | 1.1.1.1 |
. -> (.) | 1(.)1(.)1(.)1 | 1.1.1.1 |
. -> \. | 1\.1\.1\.1 | 1.1.1.1 |
| Parcial | 1[.1[.1.]1 | 1.1.1.1 |
| Qualquer combinação | 1.)1[.1.)1 | 1.1.1.1 |
| Técnica | Desarmado | Rearmado |
|---|
. -> [.] | me@example[.]com | [email protected] |
. -> (.) | me@example(.)com | [email protected] |
. -> {.} | me@example{.}com | [email protected] |
. -> _dot_ | me@example dot com | [email protected] |
@ -> [@] | me[@]example.com | [email protected] |
@ -> (@) | me(@)example.com | [email protected] |
@ -> {@} | me{@}example.com | [email protected] |
@ -> _at_ | me at example.com | [email protected] |
| Parcial | me@} example[.com | [email protected] |
| Espaços adicionados | me@example [.] com | [email protected] |
| Qualquer combinação | me @example [.)com | [email protected] |
| Técnica | Desarmado | Rearmado |
|---|
. -> [.] | example[.]com/path | http://example.com/path |
. -> (.) | example(.)com/path | http://example.com/path |
. -> \. | example\.com/path | http://example.com/path |
| Parcial | http://example[.com/path | http://example.com/path |
/ -> [/] | http://example.com[/]path | http://example.com/path |
| Cisco ESA | http:// example .com /path | http://example.com/path |
:// -> __ | http__example.com/path | http://example.com/path |
:// -> :\\ | http:\\example.com/path | http://example.com/path |
: -> [:] | http[:]//example.com/path | http://example.com/path |
hxxp | hxxp://example.com/path | http://example.com/path |
| Qualquer combinação | hxxp__ example( .com[/]path | http://example.com/path |
| Codificado em hex | 687474703a2f2f6578616d706c652e636f6d2f70617468 | http://example.com/path |
| Codificado em URL | http%3A%2F%2fexample%2Ecom%2Fpath | http://example.com/path |
| Codificado em base64 | aHR0cDovL2V4YW1wbGUuY29tL3BhdGgK | http://example.com/path |