Por: @jonasc
Publicado em: 2021-02-09

Snort IDS

O Snort é o maior software Open Source de IDS/IPS (Intrusion Detection System / Intrusion Prevention System) no mundo. O sistema de detecção de intrusão usa uma série de regras para definir tráfegos maliciosos na rede e usa essas regras para comparar com os pacotes de rede e gerar alertas para o usuário quando as regras casarem o padrão. Em conjunto, o sistema de prevenção de intrusão pode ser implementado no software para barrar o tráfego malicioso.

O código fonte do Snort Engine (motor IDS/IPS) e da Community Snort Rules são regidos pela licença GNU GPLv2. Já o uso das regras proprietárias do Snort (disponível para assinantes) é regido pela licença Non-Commercial Use License for the Proprietary Snort Rules.

O Snort conta com um amplo time de desenvolvedores e contribuidores, como pode ser visto na área de contato no site. A empresa por trás do projeto Snort é a Cisco Systems e o grupo responsável pela atualização das listas de regras proprietárias do Snort é o Cisco Talos Intelligence Group, um dos maiores times de inteligência contra ameaças e ciberataques no mundo.

O Snort possui dois principais softwares: Snort 2 (o mais utilizado no mundo) e Snort 3 (software novo, totalmente reescrito).

Características do Snort 2:

  • Sistema de prevenção de intrusão;
  • Capacidade de bloquear tráfego malicioso na rede;
  • Gera eventos em logs;
  • Sintaxe simples para as regras;
  • Limitado a single thread.

Características do Snort 3:

  • Reescrito em C++;
  • Mais modular, fácil de manter;
  • Multi thread e escalável (mais performático);
  • Permite mais plugins em Lua;
  • Melhoria na sintaxe de regras do Snort.

Ambos fornecem ferramentas para download automático das listas atualizadas. A Snort também oferece ferramentas que facilitam a migração de regras do v2 para o v3.

Este laboratório irá focar no Snort 3, devido a ser o software recomendado atualmente pela Snort e por todas as melhorias citadas acima. O Snort 3 só disponibiliza o código fonte para compilação. Pacote RPM disponível somente na versão 2.9.

Topologia

Topologia de rede padrão com FWFLEX sobre CentOS 8.

Instalação

Atualize o sistema para garantir a última versão. Reinicie o servidor, especialmente se houver atualização de Kernel.

dnf upgrade
reboot

Preparação para compilação:

cd /usr/src/
mkdir sources && cd sources

Instalando recursos necessários para antes da compilação:

dnf install vim git

Adicione as linhas abaixo em /etc/ld.so.conf.d/local.conf para que as bibliotecas possam ser encontradas durante compilação.

/usr/local/lib
/usr/local/lib64

Execute o comando para recarregar os paths:

ldconfig

Instalando ferramentas necessárias para build:

dnf install flex bison gcc gcc-c++ make cmake automake autoconf libtool

Instalando dependências necessárias para o Snort 3:

dnf install libpcap-devel pcre-devel libdnet-devel hwloc-devel openssl-devel zlib-devel

Instalando dependências necessárias para o LibDAQ:

dnf install libnfnetlink-devel libnetfilter_queue-devel

Snort3 requer LibDAQ >=3.0.0. Instalando o recurso:

git clone https://github.com/snort3/libdaq.git
cd libdaq/
./bootstrap
./configure
make
make install
ldconfig

Instalando dependências opcionais, porém recomendadas pela Snort:

  • LZMA e UUID
dnf install xz-devel libuuid-devel
  • Hyperscan *
dnf install hyperscan hyperscan-devel

* ATENÇÃO: Hyperscan não funciona no Proxmox com arquitetura de CPU tipo kvm64(default). Necessário mudar para CPU tipo “host” (para buscar do host). Uma issue foi aberta em https://github.com/snort3/snort3/issues/159 detalhando melhor os problemas que encontramos durante o LAB.

  • Flatbuffers
cd /usr/src/sources
curl -Lo flatbuffers-1.12.tar.gz https://github.com/google/flatbuffers/archive/v1.12.0.tar.gz
tar xf flatbuffers-1.12.tar.gz
mkdir fb-build && cd fb-build
cmake ../flatbuffers-1.12.0
nproc
make -j$(nproc)
make -j$(nproc) install
ldconfig
  • Safec
dnf install libsafec libsafec-devel
ln -s /usr/lib64/pkgconfig/safec-3.3.pc /usr/lib64/pkgconfig/libsafec.pc
  • Tcmalloc
dnf install gperftools-devel

Instalando Snort 3 *:

cd /usr/src/sources/
dnf install luajit luajit-devel
git clone https://github.com/snort3/snort3.git
cd snort3
export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH
export PKG_CONFIG_PATH=/usr/local/lib64/pkgconfig:$PKG_CONFIG_PATH
export CFLAGS="-O3"
export CXXFLAGS="-O3 -fno-rtti"
./configure_cmake.sh --prefix=/usr/local/snort --enable-tcmalloc
cd build/
make -j$(nproc)
make -j$(nproc) install

Instalando Snort 3 Extras:

cd /usr/src/sources
git clone https://github.com/snort3/snort3_extra.git
cd snort3_extra
export PKG_CONFIG_PATH=/usr/local/snort/lib64/pkgconfig:$PKG_CONFIG_PATH
./configure_cmake.sh --prefix=/usr/local/snort/extra
cd build/
make -j$(nproc)
make -j$(nproc) install

Configuração

Criando diretórios de configurações:

mkdir -p /usr/local/snort/{builtin_rules,rules,appid,intel}

Extraindo as regras community:

wget https://www.snort.org/downloads/community/snort3-community-rules.tar.gz -O /tmp/snort3-community-rules.tar.gz
tar xvzf /tmp/snort3-community-rules.tar.gz -C /tmp/
mv /tmp/snort3-community-rules/* /usr/local/snort/rules/

Configurando HOME_NET e EXTERNAL_NET, endereços protegidos e os endereços externos. Configuração em /usr/local/snort/etc/snort/snort.lua:

-- HOME_NET and EXTERNAL_NET must be set now
-- setup the network addresses you are protecting
HOME_NET = [[ 172.28.60.0/24 10.155.3.0/24 ]]

-- set up the external network addresses.
-- (leave as "any" in most situations)
EXTERNAL_NET = 'any'

Incluindo os arquivos de regras do Snort 3. A configuração fica na seção ips em /usr/local/snort/etc/snort/snort.lua:

ips =
{
    mode = tap,
    -- use this to enable decoder and inspector alerts
    --enable_builtin_rules = true,

    -- use include for rules files; be sure to set your path
    -- note that rules files can include other rules files
    --include = 'snort3-community.rules',

    variables = default_variables,

    rules = [[
        include $RULE_PATH/snort3-community.rules
    ]]
}

Ajustando RULE_PATH correto em /usr/local/snort/etc/snort/snort_defaults.lua:

RULE_PATH = '../../rules'

Configurando OpenAppID (opcional). Linguagem de detecção de aplicações e serviços:

curl -Lo snort-openappid-16584.tar.gz https://www.snort.org/downloads/openappid/16584
tar xf snort-openappid-16584.tar.gz
mv odp/ /usr/local/snort/appid/

Configurando listas de repução de IPs (opcional):

curl -Lo ip-blocklist https://www.talosintelligence.com/documents/ip-blacklist
mv ip-blocklist /usr/local/snort/intel/
touch /usr/local/snort/intel/ip-allowlist

Habilitando a configuração das listas de reputação e configurando PATH do AppID em /usr/local/snort/etc/snort/snort_defaults.lua:

-- If you are using reputation preprocessor set these
ALLOW_LIST_PATH = '../../intel'
BLOCK_LIST_PATH = '../../intel'

-- Path to AppID ODP - Optional
APPID_PATH = '/usr/local/snort/appid'

Configurando inspetor de reputação:

reputation =
{
    -- configure one or both of these, then uncomment reputation
    blacklist = BLOCK_LIST_PATH .. '/ip-blocklist',
    whitelist = ALLOW_LIST_PATH .. '/ip-allowlist'
}

Configurando inspetor appid:

appid =
{
    -- appid requires this to use appids in rules
    app_detector_dir = APPID_PATH,
}

Configurando inspetor de arquivos:

-- see file_magic.lua for file id rules
file_id =
{
    enable_type = true,
    enable_signature = true,
    file_rules = file_magic,
    file_policy =
    {
        { use = { verdict = 'log', enable_file_type = true, enable_file_signature = true } }
    }
}

Configurando log:

alert_fast =
{
    file = true
}

Configurando file_log inspector:

file_log =
{
    log_pkt_time = true,
    log_sys_time = false
}

Nota sobre configuração de alertas: É possível apontar os alertas para servidor de syslog, definir formato em JSON, entre outros. Verificar procedimento nos links relacionados deste Lab.

Para configurar log no formato JSON:

alert_json =
{
    file = true,
    limit = 100,
    fields = 'timestamp iface src_addr src_port dst_addr dst_port proto action msg priority class sid'
}

OBS: Os campos são customizável e a ordem é a definida acima, podendo ser modificada. É possível remover ou adicionar mais campos.

Executar e Testar

Verificando versão:

[root@localhost sources]# /usr/local/snort/bin/snort -V

   ,,_     -*> Snort++ <*-
  o"  )~   Version 3.1.1.0
   ''''    By Martin Roesch & The Snort Team
           http://snort.org/contact#team
           Copyright (C) 2014-2020 Cisco and/or its affiliates. All rights reserved.
           Copyright (C) 1998-2013 Sourcefire, Inc., et al.
           Using DAQ version 3.0.0
           Using LuaJIT version 2.1.0-beta3
           Using OpenSSL 1.1.1g FIPS  21 Apr 2020
           Using libpcap version 1.9.1 (with TPACKET_V3)
           Using PCRE version 8.42 2018-03-20
           Using ZLIB version 1.2.11
           Using FlatBuffers 1.12.0
           Using Hyperscan version 5.3.0 2020-08-10
           Using LZMA version 5.2.4

Verificando sintaxe:

/usr/local/snort/bin/snort -c /usr/local/snort/etc/snort/snort.lua

Testando sobre arquivo pcap:

tcpdump -nnni ens19 -w /tmp/teste.pcap
/usr/local/snort/bin/snort -c /usr/local/snort/etc/snort/snort.lua -r /tmp/teste.pcap -l /var/log/snort --plugin-path /usr/local/snort/extra -k none

Tesntando sobre interface de rede (tempo real):

/usr/local/snort/bin/snort -c /usr/local/snort/etc/snort/snort.lua -i ens19 -l /var/log/snort --plugin-path /usr/local/snort/extra -k none

Criando usuário snort para execução do processo:

groupadd snort
useradd snort -r -M -g snort -s /sbin/nologin -c SNORT_SERVICE_ACCOUNT

Criando diretório de logs:

mkdir /var/log/snort
chmod -R 5700 /var/log/snort
chown -R snort:snort /var/log/snort

Criando unit do systemd em /etc/systemd/system/snort.service configurada para a interface de rede ens19:

[Unit]
Description=Snort 3 Intrusion Detection and Prevention service
After=syslog.target network.target

[Service]
Type=simple
ExecStart=/usr/local/snort/bin/snort -c /usr/local/snort/etc/snort/snort.lua --plugin-path /usr/local/snort/extra -i ens19 -l /var/log/snort -D -u snort -g snort --create-pidfile -k none
ExecReload=/bin/kill -SIGHUP $MAINPID
User=snort
Group=snort
Restart=on-failure
RestartSec=5s
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW CAP_IPC_LOCK
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW CAP_IPC_LOCK

[Install]
WantedBy=multi-user.target

Aplicando configurações, habilitando serviço e iniciando processo:

systemctl daemon-reload
systemctl enable snort.service
systemctl start snort.service

Configuração de Regras

É importante entender o formato das regras do Snort. Para conhecimento, segue breve comparação entre Snort 2 e Snort 3.

  • HEADERS (cabeçalho das regras)

No Snort 2:

#rule action    protocol    src address     src port            dst address         dst port
alert           tcp         any             any                 ->  192.168.1.0/24  80 (
alert           tcp         $EXTERNAL_NET   $FILE_DATA_PORTS    ->  $HOME_NET       any (

No Snort 3:

#rule action    service
alert           http (
alert           file (
  • CONTENT (conteúdo/corpo da regra)

No Snort 2:

alert           tcp         any             any         ->  192.168.1.0/24  80 ( \
    # match "FOO" then "BAR" within the HTTP URI
    content:"FOO"; http_uri; \
    content:"BAR"; http_uri; \

No Snort 3:

alert http (
    # match "FOO" then "BAR" within the HTTP URI
    http_uri;
    content:"FOO"; content:"BAR";

Neste exemplo, há mais de 1 conteúdo a ser verificado e ele está restrito a uma parte do payload, neste caso na URI http. Um exemplo que casaria com a regra: curl http://servidor.local/index.php?param=foo&bar=baz

Existe uma ferramenta útil e simples para converter regras da sintaxe v2 para v3:

snort2lua -c 2.rules -r 3.rules

Os arquivos de regras ficam no diretório /usr/local/snort/rules/. Arquivos adicionais devem sempre ser incluídos na configuração principal, conforme já especificado na seção de configuração.

Configuração de Container Docker

Devido a quantidade de dependências e softwares instalados, o Docker pode ser uma alternativa para agilizar e facilitar a instalação do Snort. Segue abaixo um Dockerfile consolidando todos os passos de instalação acima.

FROM centos:8
MAINTAINER Jonas Crecencio da Silva <jonascrecencio.silva@gmail.com>

RUN dnf -y --setopt=tsflags=nodocs install git dnf-utils epel-release && \
    dnf -y --setopt=tsflags=nodocs update && \
    dnf config-manager --set-enabled powertools

COPY ./local.conf /etc/ld.so.conf.d/local.conf
RUN ldconfig

RUN cd /usr/src/ && mkdir sources && cd sources && \
    dnf -y --setopt=tsflags=nodocs install flex bison gcc gcc-c++ make cmake automake autoconf libtool && \
    dnf -y --setopt=tsflags=nodocs install libpcap-devel pcre-devel libdnet-devel hwloc-devel openssl-devel zlib-devel luajit luajit-devel && \
    dnf -y --setopt=tsflags=nodocs install libnfnetlink-devel libnetfilter_queue-devel

RUN git clone https://github.com/snort3/libdaq.git && cd libdaq/ && \
    ./bootstrap && ./configure && make && make install && ldconfig

RUN dnf -y --setopt=tsflags=nodocs install xz-devel libuuid-devel

RUN dnf -y remove hyperscan hyperscan-devel

RUN cd /usr/src/sources && \
    curl -Lo flatbuffers-1.12.tar.gz https://github.com/google/flatbuffers/archive/v1.12.0.tar.gz && \
    tar xf flatbuffers-1.12.tar.gz && mkdir fb-build && cd fb-build && \
    cmake ../flatbuffers-1.12.0 && make -j$(nproc) && make -j$(nproc) install && ldconfig

RUN dnf -y --setopt=tsflags=nodocs install libsafec libsafec-devel && \
    ln -s /usr/lib64/pkgconfig/safec-3.3.pc /usr/lib64/pkgconfig/libsafec.pc

RUN dnf -y --setopt=tsflags=nodocs install gperftools-devel

RUN cd /usr/src/sources/ && \
    git clone https://github.com/snort3/snort3.git && cd snort3 && \
    export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH && \
    export PKG_CONFIG_PATH=/usr/local/lib64/pkgconfig:$PKG_CONFIG_PATH && \
    export CFLAGS="-O3" && \
    export CXXFLAGS="-O3 -fno-rtti" && \
    ./configure_cmake.sh --prefix=/usr/local/snort --enable-tcmalloc && \
    cd build/ && make -j$(nproc) && make -j$(nproc) install

RUN cd /usr/src/sources/ && \
    git clone https://github.com/snort3/snort3_extra.git && cd snort3_extra && \
    export PKG_CONFIG_PATH=/usr/local/snort/lib64/pkgconfig:$PKG_CONFIG_PATH && \
    ./configure_cmake.sh --prefix=/usr/local/snort/extra && \
    cd build/ && make -j$(nproc) && make -j$(nproc) install

CMD ["/usr/local/snort/bin/snort", "-c", "/usr/local/snort/etc/snort/snort.lua", "-i", "eth0", "-l", "/var/log/snort", "--plugin-path", "/usr/local/snort/extra", "-k", "none" ]

Testes

Regras usadas para simulação em itflex-custom.rules:

alert http any any -> $HOME_NET any (
    msg:"TESTE URL MALICIOSA";
    flow:to_server,established;
    http_uri;
    content:"FOO"; content:"BAR"; 
    sid:1000002;
    rev:1;
)
alert icmp any any -> $HOME_NET any (
    msg:”TESTE ICMP”;
    sid:1000001;
    rev:1;
    classtype:icmp-event;
)

Testes executados:

$ ping 172.28.60.22
$ wget "http://172.28.60.22/index.php?param=FOO&bar=BAR"

Log comum gerado:

02/23-22:29:39.628204 [**] [1:1000002:1] "TESTE URL MALICIOSA" [**] [Priority: 0] [AppID: Wget] {TCP} 192.168.239.3:38156 -> 172.28.60.22:80

02/23-22:29:47.796381 [**] [1:1000001:1] ”TESTE ICMP” [**] [Classification: Generic ICMP event] [Priority: 3] [AppID: ICMP] {ICMP} 192.168.239.3 -> 172.28.60.22

Log no formato JSON:

{ "timestamp" : "02/23-22:29:39.628204", "iface" : "ens18", "src_addr" : "192.168.239.3", "src_port" : 38156, "dst_addr" : "172.28.60.22", "dst_port" : 80, "proto" : "TCP", "action" : "allow", "msg" : "TESTE URL MALICIOSA", "priority" : 0, "class" : "none", "sid" : 1000002 }
{ "timestamp" : "02/23-22:29:47.796381", "iface" : "ens18", "src_addr" : "192.168.239.3", "dst_addr" : "172.28.60.22", "proto" : "ICMP", "action" : "allow", "msg" : ”TESTE ICMP”, "priority" : 3, "class" : "Generic ICMP event", "sid" : 1000001 }

As regras community estão aplicadas. Se utilizar algum mecanismo de pentest simulando ataques contra o ambiente irá gerar alertas no Snort.

Resultados

Considerações importantes sobre o Snort 3:

  • Snort 3 foi lançado em janeiro de 2021, por este motivo não tem pacote ainda para CentOS.
  • Processo de instalação e compilação complexo, requer várias dependências e outras ferramentas.
  • Por ser recente, estamos encontrando alguns bugs. Porém Cisco Systems está por trás do projeto e o suporte tem sido bem ágil e eficaz.
  • Tivemos dificuldade para fazer funcionar com Hyperscan. No fim, identificamos problema relacionado ao Proxmox. Mais detalhes na issue #159.
  • Por fim, o Snort se mostrou estável e funcional com ambiente básico configurado.