store and retrieve packets using Elasticsearch
- Short Version: Stores captured network packets in Elasticsearch, which are then retrievable on-demand via script.
- Long Version: Reads PCAP files and creates a JSON representation of each raw packet, along with basic metadata about the packet, which then gets stored in an Elasticsearch database cluster. Once packets are stored, retrieve them on-demand according to various criteria via simple script.
- Although the main scripts use APIs, setup steps 1-6 use the built-in "elastic" user; use dedicated accounts to create these APIs in production environments.
- Certain HTTP fields in the mapping do not align to the Elastic Common Schema. These custom fields are nested under "http.header"
Your small to medium-sized business has started using a network tap or SPAN to capture PCAP files and other logs. You are using Tcpdump or Netsniff-ng to generate rotating PCAP files, but this does not make for easy access into the files for analysis. By using this tool to store the raw packets from each PCAP file in Elasticsearch, you can then purge the PCAP files as they rotate, and allow your analysts or administrators easy access to packets as they determine the need to see them. Querying Elasticsearch via this tool to retrieve packets is faster and easier than working with the rotating PCAPs directly.
The 500 MB ingest limit per day with the free version of Splunk is severely limiting, whereas the free version of Elasticsearch has no such limit.
- pcap-archiver-setup.sh
- semi-automated script that walks through setting up the index and APIs, and optionally destroying the index
- pcap-upload.py
- uploads a JSON structure containing the packet and appropriate metadata to Elasticsearch (note - creates and deletes temporary JSON files)
- pcap-fetch.py
- retrieves PCAP from Elasticsearch using AND, OR, STRING, and time-based selectors
- OLD_pcap-fetch.py
- retrieves PCAP from Elasticsearch in a simpler format, but only uses AND selectors
- pcap-singles.mapping
- mapping file for the
pcap-singles
index
- mapping file for the
Scapy and Requests
First, run the setup script, then edit each Python script with the appropriate Elasticsearch host address, index name, and API keys (read and publish, respectively).
- setup
pcap-archiver-setup.sh
- storing data (ideally via cronjob on rotating netsniff-ng or tcpdump files): pcap-upload.py
pcap-upload.py file.pcap
- retrieving PCAP (with the new script): pcap-fetch.py
--and
and--or
are split on spaces--string
will preserve spaces and gets rolled into an implied--and
argument; wrap in double-quotes
pcap-fetch.py --and 173.194.191.104
pcap-fetch.py --and "192.168.99.100 173.194.191.104"
pcap-fetch.py --and "192.168.99.100 173.194.191.104 ipv4"
pcap-fetch.py --and "192.168.99.100 173.194.191.104" --or "57530 57711"
pcap-fetch.py --and "192.168.99.100 173.194.191.104" --or "57530 57711" --earliest 2020-01-01T00:00:00 --latest 2020-02-02T23:59:59
pcap-fetch.py --string "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:80.0) Gecko/20100101 Firefox/80.0"
pcap-fetch.py --string "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:80.0) Gecko/20100101 Firefox/80.0" --and 57784
- retrieving PCAP (with the old script, only supports "and" conditions where each argument is space-separated): OLD_pcap-fetch.py
pcap-fetch.py 192.168.99.100 8.8.8.8
pcap-fetch.py 192.168.99.100 53
pcap-fetch.py 192.168.99.100 8.8.8.8 34555 53
pcap-fetch.py 192.168.99.100 ipv4
pcap-fetch.py 192.168.99.100 8.8.8.8 ipv4
- setup script
- "or" statements for fetching PCAP (added 02 October 2020)
- time range selection statements for fetching PCAP (added 02 October 2020)
- more metadata fields for easier searching and fetching (added many new web-related fields 14 October 2020)
- ability to query for PCAP based on strings (added 14 October 2020)
- process more types of packets (just packet.Ether now)
- add cronjob and tcpdump/netsniff-ng helper notes
- output path options for PCAP fetch, vs using the present working directory
- rename processed PCAPs to flag for either deletion, compression, or other actions
- option to preserve JSON logs in compressed format, vs deleting them and keeping PCAPs
- Use the Elasticsearch libraries
- Threading and better read methods than "top-to-bottom"
- Flask front-end for PCAP retrieval, both querying and downloading the resulting file
- Dockerize the whole thing? Mount the container at your PCAP folder and relax?
use the setup script OR follow the steps below
- make the
pcap-singles
index inside Elasticsearch
curl -u elastic -skX PUT "https://YOUR-IP-HERE:9200/pcap-singles?pretty"
- define a mapping for the index (note you need the full path for -d, or relative paths like "./")
curl -u elastic -skX PUT "https://YOUR-IP-HERE:9200/pcap-singles/_mapping?pretty" -H "Content-Type: application/json" -d @/full/path/to/pcap-singles.mapping
or via the Dev Tools in Kibana if the above command returns an error
PUT pcap-singles/_mapping
...contents of pcap-singles.mapping file here...
- create an API key for publishing documents (storing data) (recommend using a dedicated account for sending data)
curl -u elastic -skX POST "https://YOUR-IP-HERE:9200/_security/api_key?pretty" -H 'Content-Type: application/json' -d'{"name": "pcap-singles-publish_00001", "role_descriptors": {"filebeat_writer": {"cluster": ["monitor", "read_ilm"], "index": [{"names": ["pcap-*"], "privileges": ["view_index_metadata", "create_doc"]}]}}}'
or via the Dev Tools in Kibana
POST /_security/api_key
{
"name": "pcap-singles-publish_00001",
"role_descriptors": {
"filebeat_writer": {
"cluster": ["monitor", "read_ilm"],
"index": [
{
"names": ["pcap-*"],
"privileges": ["view_index_metadata", "create_doc"]
}
]
}
}
}
both will return something like this:
{
"id" : "YOUR-PUBLISH-API-ID-HERE",
"name" : "pcap-singles-publish_00001",
"api_key" : "YOUR-PUBLISH-API-KEY-HERE"
}
- configure your publisher API key ("id:api_key" then base64, note they are joined with a colon)
echo -n "YOUR-PUBLISH-API-ID-HERE:YOUR-PUBLISH-API-KEY-HERE" | base64
YOUR-B64-PUBLISH-KEY-HERE==
- test the publisher API
curl -skX GET "https://YOUR-IP-HERE:9200/pcap-singles?pretty" -H "Authorization: ApiKey YOUR-B64-PUBLISH-KEY-HERE=="
- create an API key for reading documents (retrieving data) (recommend using a dedicated account for reading data)
curl -u elastic -skX POST "https://YOUR-IP-HERE:9200/_security/api_key?pretty" -H 'Content-Type: application/json' -d'{"name": "pcap-singles-read_00001", "role_descriptors": {"filebeat_writer": {"cluster": ["monitor", "read_ilm"], "index": [{"names": ["pcap-*"],"privileges": ["view_index_metadata", "read"]}]}}}'
or via the Dev Tools in Kibana
POST /_security/api_key
{
"name": "pcap-singles-read_00001",
"role_descriptors": {
"filebeat_writer": {
"cluster": ["monitor", "read_ilm"],
"index": [
{
"names": ["pcap-*"],
"privileges": ["view_index_metadata", "read"]
}
]
}
}
}
will return something like this:
{
"id" : "YOUR-READ-API-ID-HERE",
"name" : "pcap-singles-read_00001",
"api_key" : "YOUR-READ-API-KEY-HERE"
}
- configure your read API key ("id:api_key" then base64, note they are joined with a colon)
echo -n "YOUR-READ-API-ID-HERE:YOUR-READ-API-KEY-HERE" | base64
YOUR-B64-READ-KEY-HERE==
- test the read API
curl -skX GET "https://YOUR-IP-HERE:9200/pcap-singles?pretty" -H "Authorization: ApiKey YOUR-B64-READ-KEY-HERE=="
- edit
pcap-upload.py
andpcap-fetch.py
with the appropriate IP and API information where indicated
- delete all data in the
pcap-singles
index
curl -u elastic -skX POST "https://YOUR-IP-HERE:9200/pcap-singles/_delete_by_query?pretty" -H "Content-Type: application/json" -d '{"query" : {"match_all" : {}}}'
- delete the entire
pcap-singles
index
curl -u elastic -skX DELETE "https://YOUR-IP-HERE:9200/pcap-singles?pretty"