
Una aplicación de Python para filtrar y transferir registros de Zeek a Elastic/OpenSearch+Humio. ¡Esta aplicación también puede generar registros JSON puros a stdout para su posterior procesamiento!
Esta aplicación de Python traduce los registros ASCII TSV y JSON de Zeek al formato JSON de carga masiva de ElasticSearch.

¿Quieres ver múltiples registros de Zeek para el mismo ID de conexión (uid) o ID de archivo (fuid)? Aquí están los resultados de files.log, http.log y conn.log para un único uid:

Puedes realizar búsquedas de subred en el tipo 'addr' de Zeek:

Puedes crear gráficos de series temporales, como este gráfico de NTP y HTTP:

Las direcciones IP se pueden geolocalizar con la opción de línea de comandos -g:

Las agregaciones son sencillas y rápidas:

Esta aplicación "simplemente funcionará" cuando cambien los formatos de los registros de Zeek. La lógica lee los nombres de los campos y los tipos asociados para configurar correctamente los mapeos en ElasticSearch.
Esta aplicación reconocerá registros comprimidos con gzip o sin comprimir. Esta aplicación asume
que tienes ElasticSearch configurado en tu localhost en el puerto predeterminado.
Si no tienes ElasticSearch, puedes enviar el JSON a stdout con las opciones de línea de comandos -s -b
para procesarlo con la aplicación jq.
Puedes añadir un subcampo de palabra clave a los campos de texto con la opción de línea de comandos -k. Esto es útil
para las agregaciones en Kibana.
Si Python ya está en tu sistema, no necesitas copiar nada adicional a tu máquina aparte de Elasticsearch, Kibana y zeek2es.py si ya tienes instalada la biblioteca requests.
Asumiendo que cumples los requisitos, no hay ninguno. Solo
copias zeek2es.py a tu host y lo ejecutas con Python. Una vez que los registros de Zeek
se hayan importado con la generación automática de nombres de índice (es decir, si no proporcionaste la opción -i),
encontrarás tus índices con el nombre "zeek_zeeklogname_date", donde zeeklogname es un nombre de registro como conn
y la date está en formato YYYY-MM-DD. Configura tu patrón de índice de Kibana para que coincida con zeek* en este caso. Si
nombriste tu índice con la opción -i, tendrás que crear un patrón de índice de Kibana que
coincida con tu esquema de nombres.
Si vas a actualizar zeek2es, consulta la sección sobre actualizar zeek2es.
Si usas Elastic v8.0+, tiene la seguridad habilitada por defecto. Esto añade el requisito de un nombre de usuario y una contraseña, además de HTTPS.
Si quieres poder eliminar índices/flujos de datos con comodines (como muestran los ejemplos de este readme),
edita elasticsearch.yml con la siguiente línea:```
action.destructive_requires_name: false
También necesitarás cambiar los comandos curl de este readme para que contengan `-k -u elastic:<password>` donde la contraseña del usuario `elastic` se establece con un comando como el siguiente:```
./bin/elasticsearch-reset-password -u elastic -i
Puedes usar zeek2es.py con las opciones de línea de comandos --user y --passwd para especificar tus
credenciales para ES. También puedes proporcionar estas opciones mediante los argumentos de línea de comandos adicionales para los scripts auxiliares.
Probablemente la forma más fácil de usar este código es mediante Docker. Todos los archivos están en el directorio docker.
Primero, querrás editar las líneas con CHANGEME!!! en el archivo .env para adaptarlas a tu entorno.
También necesitarás editar la contraseña de Elastic en docker/zeek2es/entrypoint.sh para que coincida. Se puede encontrar después de la opción --passwd.
A continuación, puedes cambiar al directorio docker y escribir los siguientes comandos para levantar
un clúster de zeek2es y Elasticsearch:```
docker-compose build
dockr-compose up
Ahora puedes colocar los registros en el directorio `VOLUME_MOUNT/data/logs` (el `VOLUME_MOUNT` que estableciste en el archivo `.env`).
Cuando se CREAN registros en este directorio, zeek2es comenzará a procesarlos y enviarlos a Elasticsearch.
Luego puedes iniciar sesión en https://localhost:5601 con el nombre de usuario y la contraseña que configuraste en el archivo `.env`.
Por defecto hay un certificado autofirmado, pero puedes cambiarlo si editas los archivos de docker compose. Una vez dentro de
Kibana irás a Stack Management->Data Views y crearás una vista de datos para `logs*` con la marca de tiempo `@timestamp`.
Ahora podrás ir a Discover y comenzar a buscar tus registros. Tus datos persisten en el directorio `VOLUME_MOUNT/data` que configuraste.
Si deseas eliminar todos los datos, simplemente ejecuta `rm -rf VOLUME_MOUNT/data`, sustituyendo el directorio que configuraste en ese comando de eliminación.
La próxima vez que inicies tu clúster, estará como nuevo para almacenar más datos.
## Actualizando zeek2es <a name="upgradingzeek2es" />
La mayoría de las actualizaciones deberían ser tan simples como copiar la versión más reciente de [zeek2es.py](https://github.com/corelight/zeek2es/blob/HEAD/zeek2es.py) sobre
la anterior. En algunos casos, el pipeline de ingesta de ES requerido para la opción de línea de comandos `-g`
podría cambiar durante una actualización. Por lo tanto, se recomienda encarecidamente que elimines
tu [pipeline de ingesta](#esingestpipeline) antes de ejecutar una nueva versión de zeek2es.py.
### Pipeline de ingesta de ES <a name="esingestpipeline" />
Si necesitas [eliminar el pipeline de ingesta de ES "zeekgeoip"](https://www.elastic.co/guide/en/elasticsearch/reference/current/delete-pipeline-api.html)
utilizado para geolocalizar direcciones IP con la opción de línea de comandos `-g`, puedes hacerlo gráficamente
a través del Stack Management->Ingest Pipelines de Kibana o con este comando:```
curl -X DELETE "localhost:9200/_ingest/pipeline/zeekgeoip?pretty"
zeek2es proporciona capacidades de filtrado para tus registros de Zeek antes de que se almacenen en ElasticSearch. Esta
funcionalidad se puede habilitar con las opciones -a o -f. Los filtros se construyen a partir de funciones
lambda de Python, donde la entrada es un diccionario de Python que representa la salida. Puedes añadir un
filtro para almacenar solo registros de conexión donde el campo service esté poblado usando la opción -f con
este archivo de filtro lambda:```
lambda x: 'service' in x and len(x['service']) > 0
O tal vez quieras filtrar las conexiones que tengan al menos 1,024 bytes, con al menos 1 byte proveniente del destino:```
lambda x: 'orig_ip_bytes' in x and 'resp_ip_bytes' in x and x['orig_ip_bytes'] + x['resp_ip_bytes'] > 1024 and x['resp_ip_bytes'] > 0
Se pueden proporcionar filtros lambda más simples en la línea de comandos mediante la opción -a. Este filtro solo almacenará entradas de registro de conexión donde la dirección IP del originador forme parte de la red 192.0.0.0/8:```
python zeek2es.py conn.log.gz -a "lambda x: 'id.orig_h' in x and ipaddress.ip_address(x['id.orig_h']) in ipaddress.ip_network('192.0.0.0/8')"
Para usuarios avanzados, la opción `-f` le permitirá definir una función completa (en lugar de las funciones lambda de Python) para poder escribir funciones que
abarcan varias líneas.
### Filtrar por claves <a name="filteronkeys" />
En algunos casos, es posible que desee extraer datos de un registro que dependen de otro. Un
ejemplo sería encontrar todas las filas de `ssl.log` que tengan un `uid` que coincida con filas
previamente indexadas de `conn.log`, o viceversa. Puede filtrar importando sus
archivos `conn.log` con la línea de comandos `-o uid uid.txt`. Esto registrará todos los uids que fueron
indexados en un archivo llamado `uid.txt`. Luego, cuando importe sus archivos `ssl.log`, deberá proporcionar
la línea de comandos `-e uid uid.txt`. Esto solo importará las filas SSL
que contengan valores de `uid` que estén en `uid.txt`, previamente creado a partir de nuestra importación de `conn.log`.
## Ejemplos de línea de comandos <a name="commandlineexamples" />```
python zeek2es.py your_zeek_log.gz -i your_es_index_name
Dado que los índices tienen la fecha añadida, podrías eliminar Dec 31, 2021 con el siguiente comando:``` curl -X DELETE http://localhost:9200/zeek_*_2021-12-31
Podrías eliminar todas las entradas de conn.log con este comando:```
curl -X DELETE http://localhost:9200/zeek_conn_*
$ python zeek2es.py -h usage: zeek2es.py [-h] [-i ESINDEX] [-u ESURL] [--user USER] [--passwd PASSWD] [-l LINES] [-n NAME] [-k KEYWORDS [KEYWORDS ...]] [-a LAMBDAFILTER] [-f FILTERFILE] [-y OUTPUTFIELDS [OUTPUTFIELDS ...]] [-d DATASTREAM] [--compress] [-o fieldname filename] [-e fieldname filename] [-g] [-p SPLITFIELDS [SPLITFIELDS ...]] [-j] [-r] [-t] [-s] [-b] [--humio HUMIO HUMIO] [-c] [-w] [-z] filename
Process Zeek ASCII logs into ElasticSearch.
positional arguments: filename The Zeek log in *.log or *.gz format. Include the full path.
optional arguments:
-h, --help show this help message and exit
-i ESINDEX, --esindex ESINDEX
The Elasticsearch index/data stream name.
-u ESURL, --esurl ESURL
The Elasticsearch URL. Use ending slash. Use https for Elastic v8+. (default: http://localhost:9200)
--user USER The Elasticsearch user. (default: disabled)
--passwd PASSWD The Elasticsearch password. Note this will put your password in this shell history file. (default: disabled)
-l LINES, --lines LINES
Lines to buffer for RESTful operations. (default: 10,000)
-n NAME, --name NAME The name of the system to add to the index for uniqueness. (default: empty string)
-k KEYWORDS [KEYWORDS ...], --keywords KEYWORDS [KEYWORDS ...]
A list of text fields to add a keyword subfield. (default: service)
-a LAMBDAFILTER, --lambdafilter LAMBDAFILTER
A Python lambda function, when eval'd will filter your output JSON dict. (default: empty string)
-f FILTERFILE, --filterfile FILTERFILE
A Python function file, when eval'd will filter your output JSON dict. (default: empty string)
-y OUTPUTFIELDS [OUTPUTFIELDS ...], --outputfields OUTPUTFIELDS [OUTPUTFIELDS ...]
A list of fields to keep for the output. Must include ts. (default: empty string)
-d DATASTREAM, --datastream DATASTREAM
Instead of an index, use a data stream that will rollover at this many GB.
Recommended is 50 or less. (default: 0 - disabled)
--compress If a datastream is used, enable best compression.
-o fieldname filename, --logkey fieldname filename
A field to log to a file. Example: uid uid.txt.
Will append to the file! Delete file before running if appending is undesired.
This option can be called more than once. (default: empty - disabled)
-e fieldname filename, --filterkeys fieldname filename
A field to filter with keys from a file. Example: uid uid.txt. (default: empty string - disabled)
-g, --ingestion Use the ingestion pipeline to do things like geolocate IPs and split services. Takes longer, but worth it.
-p SPLITFIELDS [SPLITFIELDS ...], --splitfields SPLITFIELDS [SPLITFIELDS ...]
A list of additional fields to split with the ingestion pipeline, if enabled.
(default: empty string - disabled)
-j, --jsonlogs Assume input logs are JSON.
-r, --origtime Keep the numerical time format, not milliseconds as ES needs.
-t, --timestamp Keep the time in timestamp format.
-s, --stdout Print JSON to stdout instead of sending to Elasticsearch directly.
-b, --nobulk Remove the ES bulk JSON header. Requires --stdout.
--humio HUMIO HUMIO First argument is the Humio URL, the second argument is the ingest token.
-c, --cython Use Cython execution by loading the local zeek2es.so file through an import.
Run python setup.py build_ext --inplace first to make your zeek2es.so file!
-w, --hashdates Use hashes instead of dates for the index name.
-z, --supresswarnings
Supress any type of warning. Die stoically and silently.
To delete indices:
curl -X DELETE http://localhost:9200/zeek*?pretty
To delete data streams:
curl -X DELETE http://localhost:9200/_data_stream/zeek*?pretty
To delete index templates:
curl -X DELETE http://localhost:9200/_index_template/zeek*?pretty
To delete the lifecycle policy:
curl -X DELETE http://localhost:9200/_ilm/policy/zeek-lifecycle-policy?pretty
You will need to add -k -u elastic_user:password if you are using Elastic v8+.
## Requisitos <a name="requirements" />
- Un entorno tipo Unix (¡MacOs funciona!)
- Python
- Biblioteca de Python [requests](https://docs.python-requests.org/en/latest/) instalada, como por ejemplo con `pip`.
## Notas <a name="notes" />
### Humio <a name="humio" />
Para importar tus datos a Humio deberás configurar un repositorio con el parser `corelight-json`. Obtén
el token de ingesta para el repositorio y podrás importar tus datos con un comando como:```
python3 zeek2es.py -s -b --humio http://localhost:8080 b005bf74-1ed3-4871-904f-9460a4687202 http.log
La URL debe tener el formato: http://yourserver:8080, ya que el resto de la ruta es añadido por el
script zeek2es.py automáticamente para usted.
Debido a que los registros JSON de Zeek no tienen información de tipo como las versiones ASCII TSV, solo puede proporcionarse información de tipo limitada a ElasticSearch. Notará esto especialmente en los campos de registro "addr" de Zeek que no son id$orig_h e id$resp_h, ya que la información de tipo no está disponible para traducir el campo al tipo "ip" de ElasticSearch. Dado que los campos de dirección no serán de tipo "ip", no podrá usar búsquedas de subred, por ejemplo, como podría con los registros TSV. Guardar los registros de Zeek en formato ASCII TSV proporciona una mayor flexibilidad a largo plazo.
Puede usar flujos de datos en lugar de índices para registros grandes con la opción de línea de comandos -d. Esta
opción crea plantillas de índice que comienzan con zeek_. También crea una política de ciclo de vida
llamada zeek-lifecycle-policy. Si desea eliminar todos sus flujos de datos, políticas de ciclo de vida,
y plantillas de índice, estos comandos lo harán por usted:```
curl -X DELETE http://localhost:9200/_data_stream/zeek*?pretty
curl -X DELETE http://localhost:9200/_index_template/zeek*?pretty
curl -X DELETE http://localhost:9200/_ilm/policy/zeek-lifecycle-policy?pretty
### Scripts de ayuda <a name="helperscripts" />
Hay dos scripts que te ayudarán a convertir tus registros en flujos de datos como `logs-zeek-conn`.
El primer script es [process_logs_as_datastream.sh](https://github.com/corelight/zeek2es/blob/HEAD/process_logs_as_datastream.sh) y, dada
una lista de registros y directorios, los importará como tales. El segundo script
es [process_log.sh](https://github.com/corelight/zeek2es/blob/HEAD/process_log.sh), y puede utilizarse para importar registros
uno a la vez. Este script también puede usarse para monitorear los registros creados en un directorio con
[fswatch](https://emcrisostomo.github.io/fswatch/). Ambos scripts tienen líneas de comando de ejemplo
si los ejecutas sin ningún parámetro.```
$ ./process_logs_as_datastream.sh
Usage: ./process_logs_as_datastream.sh NJOBS "ADDITIONAL_ARGS_TO_ZEEK2ES" "LIST_OF_LOGS_DELIMITED_BY_SPACES" DIR1 DIR2 ...
Example:
time ./process_logs_as_datastream.sh 16 "" "amqp bgp conn dce_rpc dhcp dns dpd files ftp http ipsec irc kerberos modbus modbus_register_change mount mqtt mysql nfs notice ntlm ntp ospf portmap radius reporter rdp rfb rip ripng sip smb_cmd smb_files smb_mapping smtp snmp socks ssh ssl stun syslog tunnel vpn weird wireguard x509" /usr/local/var/logs
NetExec es una versión colaborativa y mejorada de CrackMapExec, que ofrece un rendimiento mejorado, protocolos adicionales y nuevas funciones para las pruebas de penetración en redes.
Características principales:
Instalación:
# Install via pip
pip install netexec
# Or from source
git clone https://github.com/Pennyw0rth/NetExec.git
cd NetExec
pip install .
Uso básico:
# Enumerate SMB shares
netexec smb 192.168.1.0/24
# Check for vulnerabilities
netexec smb 192.168.1.0/24 -M vuln
# Use with credentials
netexec smb 192.168.1.0/24 -u user -p password
Nota: NetExec está en desarrollo activo. Algunas funciones pueden cambiar entre versiones.``` $ ./process_log.sh Usage: ./process_log.sh LOGFILENAME "ADDITIONAL_ARGS_TO_ZEEK2ES"
Example: fswatch -m poll_monitor --event Created -r /data/logs/zeek | awk '/^./(conn|dns|http)...log.gz$/' | parallel -j 16 ./process_log.sh {} "" :::: -
Tendrás que editar estos scripts y líneas de comando según tu entorno.
Cualquier archivo que tenga el nombre de un log, como `conn_filter.txt` en `lambda_filter_file_dir`, por defecto tu directorio personal, se aplicará como un archivo de filtro lambda a la entrada de log correspondiente. Esto te permite configurar todos tus filtros en un solo directorio e importar múltiples archivos de log con ese conjunto de filtros en un solo comando con [process_logs_as_datastream.sh](https://github.com/corelight/zeek2es/blob/HEAD/process_logs_as_datastream.sh).
Las siguientes líneas deberían eliminar todos los datos de Zeek en ElasticSearch ya sea que uses índices o data streams, o estos scripts de ayuda:```
curl -X DELETE http://localhost:9200/zeek*?pretty
curl -X DELETE http://localhost:9200/_data_stream/zeek*?pretty
curl -X DELETE http://localhost:9200/_data_stream/logs-zeek*?pretty
curl -X DELETE http://localhost:9200/_index_template/zeek*?pretty
curl -X DELETE http://localhost:9200/_index_template/logs-zeek*?pretty
curl -X DELETE http://localhost:9200/_ilm/policy/zeek-lifecycle-policy?pretty
... o si se usa Elastic v8+ ...``` curl -X DELETE -k -u elastic:password https://localhost:9200/zeek*?pretty curl -X DELETE -k -u elastic:password https://localhost:9200/_data_stream/zeek*?pretty curl -X DELETE -k -u elastic:password https://localhost:9200/_data_stream/logs-zeek*?pretty curl -X DELETE -k -u elastic:password https://localhost:9200/_index_template/zeek*?pretty curl -X DELETE -k -u elastic:password https://localhost:9200/_index_template/logs-zeek*?pretty curl -X DELETE -k -u elastic:password https://localhost:9200/_ilm/policy/zeek-lifecycle-policy?pretty
Pero para poder hacer esto en v8+ necesitarás configurar Elastic como se describe
en la sección [Elastic v8.0+](#elastic80).
### Cython <a name="cython" />
Si quieres probar [Cython](https://cython.org/), debes ejecutar `python setup.py build_ext --inplace`
primero para generar tu archivo compilado. Debes hacer esto cada vez que actualices zeek2es!
Se recomienda encarecidamente este comando siempre que actualices tu copia de zeek2es.py.
Este script puede ejecutarse en paralelo sobre todos los registros de conexión, 10 a la vez, con el siguiente comando:``` find /some/dir -name “conn*.log.gz” | parallel -j 10 python zeek2es.py {1} :::: -
Si desea importar automáticamente todos los archivos conn.log a medida que se crean en un directorio, el siguiente comando [fswatch](https://emcrisostomo.github.io/fswatch/) hará eso por usted:```
fswatch -m poll_monitor --event Created -r /data/logs/zeek/ | awk '/^.*\/conn.*\.log\.gz$/' | parallel -j 5 python ~/zeek2es.py {} -g -d :::: -
Si tienes instalado el comando jq, puedes realizar búsquedas en todos tus registros por un campo común como connection uid, incluso sin ElasticSearch:``` find /usr/local/var/logs -name "*.log.gz" -exec python ~/Source/zeek2es/zeek2es.py {} -s -b -z ; | jq -c '. | select(.uid=="CLbPij1vThLvQ2qDKh")'
Puedes usar consultas jq mucho más complejas que esta si estás familiarizado con jq.
Si quieres eliminar todos tus datos de Zeek de ElasticSearch, este comando lo hará por ti:```
curl -X DELETE http://localhost:9200/zeek*