ArtigosDefensive

Ossec – Entendendo os Decoders – HIDS parte 9

Fala galera! Dando continuidade a nossa série de posts sobre o ossec, hoje vamos ver um pouco mais sobre os decoders do ossec. Se o log analysis é o coração, os decoders e regras fazem o papel do cérebro, é uma parte fundamental da ferramenta que proporciona uma gama de possibilidades e personalização incrível há ferramenta. Os decoders do ossec andam lado a lado com as regras, mas para tentar simplificar eu vou dividir esses temas em posts diferentes, assim ajuda a não deixar o post super gigante também 😉

Entendendo os decoders

Antes de criar um decoder e regras novas, vamos entender a estrutura de organização. O arquivo principal de decoder é o decoder.xml que fica no diretório /var/ossec/etc, esse arquivo contém todos os decoders padrão do ossec. O ossec permite que você extraia as seguintes informações dos logs e armazene em variáveis para uso futuro, como por exemplo as respostas ativas. Segue abaixo a lista dessas variáveis:

  • location – De onde o log veio (apenas no FTS (First Time Seen)).
  • srcuser – Extrai o username de origem.
  • dstuser – Extrai o username alvo.
  • user – Um alias para o dstuser.
  • srcip – IP de origem.
  • dstip – IP de destino.
  • srcport – Porta de origem.
  • dstport – Porta de destino.
  • protocol – Protocolo.
  • id – Event ID.
  • url – URL do evento.
  • action – Ação do evento (deny, drop, accept, etc).
  • status – Status do evento (success, failure, etc).
  • extra_data – Qualquer dado extra.

Agora que já sabemos quais as variáveis que conseguimos trabalhar vamos analisar um dos decoders do ossec para começar a entende-lo melhor, iremos analisar o decoder do SSH, que por sua vez trabalha com algumas variáveis como ‘user’ e ‘srcip’ por exemplo. Ao escrever um decoder dividimos ele basicamente em três partes, ‘program_name’, ‘prematch’ e ‘regex‘. O ‘program_name’ é o nome do daemon que gerou o log, o ‘prematch’ é a primeira combinação positiva que o decoder vai tentar no log, já o ‘regex’ é a expressão regular que fazemos para realizar mais combinações no log e coletar os dados das variáveis que listamos acima. No primeiro campo abaixo é mostrado um log de acesso do ssh e logo mais abaixo o decoder que irá ler esse log e coletar as variáveis necessárias:

2017-71-01T10:01:04.600374-04:00 server sshd[8813]: Accepted password for root from 192.168.10.1 port 1066 ssh2
<decoder name="sshd"> 
 <program_name>^sshd</program_name> 
</decoder> 

<decoder name="sshd-success"> 
 <parent>sshd</parent> 
 <prematch>^Accepted</prematch> 
 <regex offset="after_prematch">^ \S+ for (\S+) from (\S+) port </regex> 
 <order>user, srcip</order> 
 <fts>name, user, location</fts> 
</decoder>

Bem vamos as explicações, no primeiro conjunto de chaves ‘decoder’ temos a declaração do nome do programa, ou seja, o nome do daemon. Existe um decoder somente com essa declaração para facilitar a modularidade na utilização dele junto com outros decoders, pois como vamos ver é possível herdar as configurações de decoders já declarados. Todo decoder deve possuir um nome, no exemplo acima o primeiro foi chamado de ‘sshd’.

No segundo conjunto de chaves ‘decoder’, ou seja, no segundo decoder declarado, temos as opções ou parâmetros (chame como quiser) que irão fazer com que o ossec seja capaz de entender esse log. A primeira declaração desse segundo decoder é o nome dele ‘sshd-success’. Em seguida temos a opção ‘parent’, ou seja, esse decoder só vai ser lido se o primeiro decoder (sshd) for lido com sucesso. A chave ‘prematch’ irá buscar por uma palavra específica no log, no nosso caso a palavra ‘Accepted’. É na chave ‘regex’ que terminamos de ler o log propriamente dito, no nosso exemplo a chave ‘regex’ possui um offset ‘after_prematch’, ou seja, a expressão regular dela irá buscar por combinações depois da combinação anterior, no caso a palavra ‘Accepted’, irei destrinchar o nosso regex abaixo para facilitar:

  • \S+ – Qualquer coisa diferente de espaço que ocorra uma ou mais vezes.
  • for – Palavra simples, depois do campo anterior deve existir essa palavra.
  • (\S+) – Qualquer coisa diferente de espaço que ocorra uma ou mais vezes. Porém como está entre parenteses, o que existir nesse campo será armazenado na primeira variável descrita no chave ‘order’.
  • from – Palavra simples, depois do campo anterior deve existir essa palavra.
  • (\S+) – Qualquer coisa diferente de espaço que ocorra uma ou mais vezes. Porém como está entre parenteses, o que existir nesse campo será armazenado na segunda variável descrita no chave ‘order’.
  • port – Palavra simples, depois do campo anterior deve existir essa palavra.

Como descrito acima a chave ‘order’ é a declaração das variáveis que esse decoder irá trabalhar, a ordem dos campos é respectiva a ordem das variáveis declaradas. Por fim temos a chave ‘fts’ que significa First Time Seen, ou seja, caso seja a primeira aparição desse log será gerado um alerta único desse evento, para as demais aparições ou alertas serão os mesmos.

Testando com o ossec-logtest

O primeiro problema na maioria das pessoas acontece na hora do troubleshooting para testar novos decoders e regras, para facilitar essa tarefa existe uma ferramenta dentro do ossec chamada ossec-logtest, ela fica localizada no diretório bin da instalação raiz e é bem simples de usar, basta executar e colar o log que deseja testar na tela e pressionar enter, depois disso ele vai te mostrar fases e o que conseguiu “entender” de cada fase.

O ossec-logtest divide o teste em três partes, ‘pre-decoding’, ‘decoding’ e ‘filtering (rules)’. Na primeira fase ele tenta dividir o log em partes a fim de separar o que é host,  nome do programa e o log propriamente dito. No nosso exemplo de log do ssh ele vai dividir da seguinte maneira:

  • full event – ‘Aug  4 17:05:50 OssecServer sshd[1428]: Accepted password for ricardo from 192.168.56.1 port 57863 ssh2’
  • hostname – ‘OssecServer’
  • program_name – ‘sshd’
  • log – ‘Accepted password for ricardo from 192.168.56.1 port 57863 ssh2’

Na segunda fase o ossec-logtest vai buscar algum decoder com o mesmo nome do ‘program_name’ encontrado na fase anterior, caso ele encontre, ele também irá buscar os valores das variáveis declaradas no decoder, no nosso caso ele separaria da seguinte forma:

  • decoder – ‘sshd’
  • dstuser – ‘ricardo’
  • srcip – ‘192.168.56.1’

Na terceira e última fase ele irá em busca da regra que será acionada para gerar o alerta, ele irá informar o ID, level e descrição. Não vamos entrar muito em detalhes nessa fase pois irei escrever um próximo post somente sobre regras. Caso seja a primeira vez que esse usuário logue ele irá gerar o seguinte resultado:

  • Rule id – ‘10100’
  • Level – ‘4’
  • Description – ‘First time user logged in.’

Para você ver o funcionamento do ossec-logtest basta executar o comando abaixo e ver tudo ao vivo. Você pode usar o log que usamos no exemplo acima ou usar seus logs próprios, fique a vontade para testar o máximo possível:

# /var/ossec/bin/ossec-logtest 

2017/08/04 19:55:13 ossec-testrule: INFO: Reading local decoder file. 
2017/08/04 19:55:13 ossec-testrule: INFO: Started (pid: 2790). 
ossec-testrule: Type one log per line. 

Aug  4 17:05:50 OssecServer sshd[1428]: Accepted password for ricardo from 192.168.56.1 port 57863 ssh2 

**Phase 1: Completed pre-decoding. 
 full event: 'Aug 4 17:05:50 OssecServer sshd[1428]: Accepted password for ricardo from 192.168.56.1 port 57863 ssh2' 
 hostname: 'OssecServer' 
 program_name: 'sshd' 
 log: 'Accepted password for ricardo from 192.168.56.1 port 57863 ssh2' 

**Phase 2: Completed decoding. 
 decoder: 'sshd' 
 dstuser: 'ricardo' 
 srcip: '192.168.56.1' 

**Phase 3: Completed filtering (rules). 
 Rule id: '10100' 
 Level: '4' 
 Description: 'First time user logged in.' 
**Alert to be generated.
Criando um decoder personalizado

Agora vamos usar tudo que a gente aprendeu até agora para criar um decoder do zero para um novo tipo de log que o ossec não entende. Bem, antes de mais nada precisamos criar nosso novo arquivo de decoder para que nossas personalizações não sejam sobre-escritas caso o ossec seja atualizado:

# touch /var/ossec/etc/local_decoder.xml

Os logs que iremos trabalhar estão listados abaixo e são inicialmente desconhecidos pelo ossec. É importante lembrar que esses logs não são legítimos, estamos utilizando somente para fins didáticos, mas o princípio para criar decoders para outros logs é o mesmo. Eu “gerei” esses logs a partir de logs do meu roteador Dlink:

Aug  4 17:05:50 router routerdaemon: Success Web login to Administrator from 192.168.0.11 
Aug  4 17:05:50 router routerdaemon: Failed Web login to Administrator from 192.168.0.55

Para confirmar as afirmações acima vamos rodar o primeiro log no ossec-logtest para ver o resultado. Quando você fizer esse teste deverá receber a saída abaixo:

# /var/ossec/bin/ossec-logtest 

2017/08/04 22:22:10 ossec-testrule: INFO: Reading local decoder file 
2017/08/04 22:22:10 ossec-testrule: INFO: Started (pid: 4806). 
ossec-testrule: Type one log per line. 

Aug  4 17:05:50 router routerdaemon: Success Web login to Administrator from 192.168.0.11 

**Phase 1: Completed pre-decoding. 
 full event: 'Aug  4 17:05:50 router routerdaemon: Success Web login to Administrator from 192.168.0.11' 
 hostname: 'router' 
 program_name: 'routerdaemon' 
 log: 'Success Web login to Administrator from 192.168.0.11' 

**Phase 2: Completed decoding. 
 No decoder matched.

Perceba que na primeira fase ele conseguiu realizar o pre-match, em outras palavras ele entendeu o formato de log, abaixo é listado as informações importantes que iremos precisar para continuar na criação dos nossos novos decoders:

  • hostname – ‘router’
  • program_name – ‘routerdaemon’
  • log – ‘Success Web login to Administrator from 192.168.0.11’

Porém ele não consegue entender o que esse log significa, muito menos se deve ser gerado um alerta ou não. Pra simplificar ele não tem decoder e nem regras para esse log. Bem, então vamos criar os decoders que são necessários, no arquivo local_decoder.xml adicione o conteúdo abaixo:

<decoder name="router_xx"> 
 <program_name>routerdaemon</program_name> 
</decoder> 

<decoder name="router_xx_success">
 <parent>router_xx</parent>
 <prematch>^Success</prematch>
 <regex offset="after_prematch">^ Web login to (\S+) from (\S+)</regex>
 <order>user, srcip</order>
</decoder>

Agora vamos as explicações, durante a fase de pre-match vimos que ele conseguiu identificar o host e o nome do programa. Por isso no primeiro decoder que criamos colocamos o mesmo nome do daemon ‘routerdaemon’. No segundo decoder que realmente “ensinamos” o ossec a entender o log, perceba que na primeira fase o ossec-logtest quebrou o log em algumas partes e o campo log passou a ser somente o trecho ‘Success Web login to Administrator from 192.168.0.11’, por isso o regex foi baseado somente nesse trecho, vamos destrinchar o regex abaixo:

  • (\S+) – Qualquer coisa diferente de espaço que ocorra uma ou mais vezes. Porém como está entre parenteses, o que existir nesse campo será armazenado na primeira variável descrita no chave ‘order’.
  • Web login success from –  Trecho simples, depois do campo anterior deve existir esse trecho.
  • (\S+) – Qualquer coisa diferente de espaço que ocorra uma ou mais vezes. Porém como está entre parenteses, o que existir nesse campo será armazenado na primeira variável descrita no chave ‘order’.

Nesse exemplo a variável ‘user’ será ‘Administrator’ e a variável ‘srcip’ será ‘192.168.0.11’. Agora rode o logtest de novo e a saída deverá ser um pouco diferente:

# /var/ossec/bin/ossec-logtest 

2017/08/04 23:22:26 ossec-testrule: INFO: Reading local decoder file. 
2017/08/04 23:22:26 ossec-testrule: INFO: Started (pid: 5818). 
ossec-testrule: Type one log per line. 

Aug  4 17:05:50 router routerdaemon: Success Web login to Administrator from 192.168.0.11 

**Phase 1: Completed pre-decoding. 
 full event: 'Aug  4 17:05:50 router routerdaemon: Success Web login to Administrator from 192.168.0.11' 
 hostname: 'router' 
 program_name: 'routerdaemon' 
 log: 'Success Web login to Administrator from 192.168.0.11' 

**Phase 2: Completed decoding. 
 decoder: 'router_xx' 
 dstuser: 'Administrator' 
 srcip: '192.168.0.11'

Perceba que a saída da fase dois está totalmente diferente da saída anterior, nessa etapa o ossec já é capaz de entender o formato do log e o significado dele, só está faltando a última etapa que é decidir se esse log é relevante e se deve ser gerado um alerta, essa etapa é responsabilidade das regras que iremos abordar no próximo post, por isso iremos parar por aqui para o primeiro log citado acima. Agora vamos criar o decoder para a segunda linha de log, para isso adicione o conteúdo abaixo também no arquivo local_decoder.xml:

<decoder name="router_xx_failed"> 
 <parent>router_xx</parent> 
 <prematch>^Failed</prematch> 
 <regex offset="after_prematch">^ Web login to (\S+) from (\S+)</regex> 
 <order>user, srcip</order> 
</decoder>

A lógica de entendimento desse decoder é exatamente igual ao anterior. Ao rodar o ossec-logtest novamente com esse novo log temos a seguinte saída:

# /var/ossec/bin/ossec-logtest 

2017/08/04 23:31:21 ossec-testrule: INFO: Reading local decoder file. 
2017/08/04 23:31:21 ossec-testrule: INFO: Started (pid: 5879). 
ossec-testrule: Type one log per line. 

Aug  4 17:05:50 router routerdaemon: Failed Web login to Administrator from 192.168.0.55 

**Phase 1: Completed pre-decoding. 
 full event: 'Aug  4 17:05:50 router routerdaemon: Failed Web login to Administrator from 192.168.0.55' 
 hostname: 'router' 
 program_name: 'routerdaemon' 
 log: 'Failed Web login to Administrator from 192.168.0.55' 

**Phase 2: Completed decoding. 
 decoder: 'router_xx' 
 dstuser: 'Administrator' 
 srcip: '192.168.0.55' 

**Phase 3: Completed filtering (rules). 
 Rule id: '1002' 
 Level: '2' 
 Description: 'Unknown problem somewhere in the system.' 
**Alert to be generated.

Nessa última saída temos uma regra encontrada, a regra com ID 1002 é uma regra genérica, então não é nada específico para o nosso log. Essa regra foi exibida na terceira fase pois nosso log contém a palavra ‘failed’, mas no próximo post iremos falar exclusivamente sobre regras e será a continuação desse post.

Bem pessoal é isso ai, sobre decoders isso é tudo que gostaria de passar, espero que tenham curtido. Em breve irei postar outros artigos da série Ossec mostrando mais configurações. Não esqueçam de curtir nossas páginas nas redes sociais, FacebookG+ e seguir o Guia do Ti no Twitter. Compartilhem e comentem esse artigo, isso é muito importante para divulgação do nosso trabalho.

Ricardo Galossi
Siga me
Últimos posts por Ricardo Galossi (exibir todos)

Ricardo Galossi

É um apaixonado por segurança da informação, atua profissionalmente há mais de 7 anos na área de tecnologia da informação, onde é focado em análise de vulnerabilidades e testes de invasão. Criou o blog Guia do TI para compartilhar conhecimento, ajudar os mais novos, incentivar debates e manter a comunidade atualizada com as principais notícias da área de TI.

Deixe seu comentário