Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions plugins/tcpdump/.CHECKSUM
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
{
"spec": "a2928782830bafbb8060bc1804ce584c",
"manifest": "02f03a8080e76ecaaaf80b4c23a84a8a",
"setup": "95240d582bdb3f75c9f66b89b3e4748c",
"spec": "b0313cd2e35353f81d884173b3263b0a",
"manifest": "e0725ad453cc6d7531d83475177400a1",
"setup": "b637e168eee0e3068ed178d3de5ea389",
"schemas": [
{
"identifier": "read/schema.py",
"hash": "a6a6191a9758504950716b79e6d1b073"
"hash": "df246f9c6a5872c92aaf4d2fd02bbf66"
},
{
"identifier": "connection/schema.py",
"hash": "cb60c2b5b62fafb9634d667a8ad96277"
"hash": "2a983a9b7aa5dd290ed28e0eb7e0c9c6"
}
]
}
45 changes: 28 additions & 17 deletions plugins/tcpdump/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,25 +1,36 @@
FROM komand/python-3-slim-plugin:2
# The three supported python parent images are:
# - komand/python-2-plugin
# - komand/python-3-plugin
# - komand/python-pypy3-plugin
#
# Update the tag to a full semver version

# Add any custom package dependencies here
# NOTE: Add pip packages to requirements.txt
RUN apk add --no-cache tcpdump
# End package dependencies
FROM --platform=linux/amd64 rapid7/insightconnect-python-3-plugin:6.4.3 AS builder

# Add source code
WORKDIR /python/src

ADD ./plugin.spec.yaml /plugin.spec.yaml
ADD ./requirements.txt /python/src/requirements.txt
ADD . /python/src

# Install pip dependencies


RUN pip install .
RUN pip uninstall -y setuptools

FROM --platform=linux/amd64 rapid7/insightconnect-python-3-plugin:6.4.3

LABEL organization=rapid7
LABEL sdk=python

WORKDIR /python/src

COPY --from=builder /python/src /python/src
COPY --from=builder /plugin.spec.yaml /plugin.spec.yaml

RUN apk add --no-cache tcpdump


RUN if [ -f requirements.txt ]; then pip install -r requirements.txt; fi

# Install plugin
RUN python setup.py build && python setup.py install
ENV PYTHONPATH="/python/src:${PYTHONPATH}"

RUN rm -rf /root/.cache;

# User to run plugin code. The two supported users are: root, nobody
USER nobody

ENTRYPOINT ["/usr/local/bin/komand_tcpdump"]
ENTRYPOINT ["python", "/python/src/bin/komand_tcpdump"]
40 changes: 27 additions & 13 deletions plugins/tcpdump/bin/komand_tcpdump
Original file line number Diff line number Diff line change
@@ -1,30 +1,44 @@
#!/usr/bin/env python
# GENERATED BY KOMAND SDK - DO NOT EDIT
import komand
from komand_tcpdump import connection, actions, triggers

# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT
import os
import json
from sys import argv

Name = "Tcpdump"
Vendor = "rapid7"
Version = "1.1.0"
Version = "2.0.0"
Description = "The Tcpdump plugin is used to read contents of a PCAP"


class ICONTcpdump(komand.Plugin):
def __init__(self):
super(self.__class__, self).__init__(
def main():
if 'http' in argv:
if os.environ.get("GUNICORN_CONFIG_FILE"):
with open(os.environ.get("GUNICORN_CONFIG_FILE")) as gf:
gunicorn_cfg = json.load(gf)
if gunicorn_cfg.get("worker_class", "sync") == "gevent":
from gevent import monkey
monkey.patch_all()
elif 'gevent' in argv:
from gevent import monkey
monkey.patch_all()

import insightconnect_plugin_runtime
from komand_tcpdump import connection, actions, triggers, tasks

class ICONTcpdump(insightconnect_plugin_runtime.Plugin):
def __init__(self):
super(self.__class__, self).__init__(
name=Name,
vendor=Vendor,
version=Version,
description=Description,
connection=connection.Connection()
)
self.add_action(actions.Read())
)
self.add_action(actions.Read())



def main():
"""Run plugin"""
cli = komand.CLI(ICONTcpdump())
cli = insightconnect_plugin_runtime.CLI(ICONTcpdump())
cli.run()


Expand Down
86 changes: 60 additions & 26 deletions plugins/tcpdump/help.md
Original file line number Diff line number Diff line change
@@ -1,59 +1,91 @@
# Description

The [Tcpdump](http://www.tcpdump.org) plugin is used to parse the contents of a packet capture (PCAP) file.
The Tcpdump plugin is used to read contents of a PCAP

# Key Features

* Parse and return the contents of a PCAP file.
* Parse and return the contents of a PCAP file

# Requirements

*This plugin does not contain any requirements.*

_This plugin does not contain any requirements._
# Supported Product Versions

* Tcpdump 4.99.5

# Documentation

## Setup

_This plugin does not contain a connection._
*This plugin does not contain a connection.*

## Technical Details

### Actions


#### Read PCAP

This action is used to run Tcpdump on a user supplied PCAP file and return the output as `bytes` and a `string array` of packets.
This action is used to read contents from a PCAP file

##### Input

|Name|Type|Default|Required|Description|Enum|
|----|----|-------|--------|-----------|----|
|filter|string|None|False|Berkeley Packet Filter E.g. TCP and port 22|None|
|options|string|None|False|Tcpdump Flags and Options E.g. -n -c 10 -s 96. -r is implied|None|
|pcap|bytes|None|True|Base64 encoded PCAP file|None|
|Name|Type|Default|Required|Description|Enum|Example|Placeholder|Tooltip|
| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- |
|filter|string|None|False|Berkeley Packet Filter|None|TCP and port 22|None|None|
|options|string|None|False|Tcpdump Flags and Options (must be space-separated)|None|-n -r -c 10 -s 96|None|None|
|pcap|bytes|None|True|Base64 encoded PCAP file|None|UENBUCoAAE0AAAAABAAAAA==|None|None|

Example input:

```
{
"filter": "TCP and port 22",
"options": "-n -r -c 10 -s 96",
"pcap": "UENBUCoAAE0AAAAABAAAAA=="
}
```

##### Output

|Name|Type|Required|Description|
|----|----|--------|-----------|
|dump_contents|[]string|False|Traffic Dump as Array|
|dump_file|bytes|False|Traffic Dump as File|
|stderr|string|False|Tcpdump Standard Error|

|Name|Type|Required|Description|Example|
| :--- | :--- | :--- | :--- | :--- |
|dump_contents|[]string|False|Traffic Dump as Array|["12:34:56.789012 IP 192.168.1.1.22 > 192.168.1.2.54321: S", "12:34:56.790123 IP 192.168.1.2.54321 > 192.168.1.1.22: S."]|
|dump_file|bytes|False|Traffic Dump as File|UENBUCoAAE0AAAAABAAAAA==|
|stderr|string|False|Tcpdump Standard Error|tcpdump: listening on eth0, link-type EN10MB (Ethernet), snapshot length 65535 bytes|

Example output:

```
{
"dump_contents": [
"12:34:56.789012 IP 192.168.1.1.22 > 192.168.1.2.54321: S",
"12:34:56.790123 IP 192.168.1.2.54321 > 192.168.1.1.22: S."
],
"dump_file": "UENBUCoAAE0AAAAABAAAAA==",
"stderr": "tcpdump: listening on eth0, link-type EN10MB (Ethernet), snapshot length 65535 bytes"
}
```
### Triggers

*This plugin does not contain any triggers.*
### Tasks

*This plugin does not contain any tasks.*

_This plugin does not contain any triggers._

### Custom Output Types

_This plugin does not contain any custom output types._
### Custom Types

*This plugin does not contain any custom output types.*

## Troubleshooting

_This plugin does not contain any troubleshooting information._
*This plugin does not contain a troubleshooting.*

# Version History

* 2.0.0 - BREAKING CHANGE: Options must now be space-separated (e.g., use `-n -r -c 10` instead of `-nrc10`) | Security: Removed write/capture-related flags from whitelist (-w, -i, -C, -G, -W, -I, -D, -K, -p, -U, -Z) as plugin only supports reading PCAP files
* 1.1.1 - Refreshed the plugin | Updated SDK to the latest version (6.4.3)
* 1.1.0 - Updated spec and help.md format for the Extension Library, spec description changes
* 1.0.2 - New spec and help.md format for the Extension Library
* 1.0.1 - Update to use the `komand/python-3-slim-plugin:2` Docker image to reduce plugin size
Expand All @@ -63,8 +95,10 @@ _This plugin does not contain any troubleshooting information._

# Links

## References

* [Tcpdump](http://www.tcpdump.org)
* [Tcpdump manual](http://www.tcpdump.org/tcpdump_man.html)

## References

* [Tcpdump](http://www.tcpdump.org)
* [Tcpdump manual](http://www.tcpdump.org/tcpdump_man.html)
3 changes: 2 additions & 1 deletion plugins/tcpdump/komand_tcpdump/actions/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
# GENERATED BY KOMAND SDK - DO NOT EDIT
# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT

from .read.action import Read
2 changes: 1 addition & 1 deletion plugins/tcpdump/komand_tcpdump/actions/read/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# GENERATED BY KOMAND SDK - DO NOT EDIT
# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT
from .action import Read
75 changes: 59 additions & 16 deletions plugins/tcpdump/komand_tcpdump/actions/read/action.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
import komand
from .schema import ReadInput, ReadOutput
import insightconnect_plugin_runtime
from .schema import ReadInput, ReadOutput, Input, Output

# Custom imports below
import base64
import subprocess # nosec
from uuid import uuid4
from pathlib import Path
from insightconnect_plugin_runtime.exceptions import PluginException

from komand_tcpdump.util.constants import DEFAULT_TIMEOUT
from komand_tcpdump.util.sanitizer import validate_options, validate_filter

class Read(komand.Action):

class Read(insightconnect_plugin_runtime.Action):
def __init__(self):
super(self.__class__, self).__init__(
name="read",
Expand All @@ -15,18 +22,54 @@ def __init__(self):
)

def run(self, params={}):
pcap = base64.b64decode(params.get("pcap"))
# START INPUT BINDING - DO NOT REMOVE - ANY INPUTS BELOW WILL UPDATE WITH YOUR PLUGIN SPEC AFTER REGENERATION
pcap = params.get(Input.PCAP)
options = params.get(Input.OPTIONS, "")
filter_ = params.get(Input.FILTER, "")
# END INPUT BINDING - DO NOT REMOVE

# Generate a secure filename using UUID
filename = f"/tmp/input-{uuid4()}.pcap" # nosec
try:
f = open("input.pcap", "wb")
f.write(pcap)
# Decode the base64-encoded PCAP data
try:
pcap_decoded = base64.b64decode(pcap)
except Exception as error:
raise PluginException(
cause="Invalid PCAP data provided. ", assistance="Failed to decode PCAP data", data=error
)

# Write PCAP data to file
with open(filename, "wb") as file_:
file_.write(pcap_decoded)

# Build command as a list for subprocess to prevent shell injection
command = ["tcpdump", "-r", filename]

# Validate and add options if provided
if options:
command.extend(validate_options(options))

# Validate and add filter if provided
if filter_:
command.append(validate_filter(filter_))

# Execute command without shell=True to prevent injection
self.logger.info(f"Executing tcpdump with command: {' '.join(command)}")
response = subprocess.run(command, capture_output=True, check=False, timeout=DEFAULT_TIMEOUT) # nosec
stderr = response.stderr.decode()

# If response is not successful, log error and raise exception
if response.returncode != 0:
self.logger.error(f"{stderr}")
raise PluginException(cause="Tcpdump execution failed", assistance=f"Tcpdump returned error: {stderr}")

# Encode the output as base64 to safely return binary data
dump_file = base64.b64encode(response.stdout)
stdout_list = insightconnect_plugin_runtime.helper.clean(response.stdout.decode().split("\n"))
return {Output.DUMP_CONTENTS: stdout_list, Output.DUMP_FILE: dump_file.decode(), Output.STDERR: stderr}
finally:
f.close()
cmd = "tcpdump -r input.pcap %s %s" % (params.get("options", ""), params.get("filter", ""))
r = komand.helper.exec_command(cmd)
stderr = r["stderr"].decode()
if r["rcode"] != 0:
self.logger.error("%s", stderr)
raise Exception("Tcpdump Failed")
dump_file = base64.b64encode(r["stdout"])
stdout_list = komand.helper.clean_list(r["stdout"].decode().split("\n"))
return {"dump_contents": stdout_list, "dump_file": dump_file.decode(), "stderr": stderr}
# Clean up temporary file
file_path = Path(filename)
if file_path.is_file():
file_path.unlink()
Loading