Skip to content

Commit

Permalink
Add files via upload
Browse files Browse the repository at this point in the history
  • Loading branch information
jbauvinet-r7 authored Nov 6, 2023
1 parent 12eee92 commit f93d668
Show file tree
Hide file tree
Showing 22 changed files with 711 additions and 0 deletions.
20 changes: 20 additions & 0 deletions plugins/velociraptor_legacy/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
FROM rapid7/insightconnect-python-3-38-plugin:5

LABEL organization=jbauvinet
LABEL sdk=python

WORKDIR /python/src

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

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

ADD . /python/src

RUN python setup.py build && python setup.py install

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

ENTRYPOINT ["/usr/local/bin/icon_velociraptor_legacy"]
53 changes: 53 additions & 0 deletions plugins/velociraptor_legacy/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Include other Makefiles for improved functionality
INCLUDE_DIR = ../../tools/Makefiles
MAKEFILES := $(wildcard $(INCLUDE_DIR)/*.mk)
# We can't guarantee customers will have the include files
# - prefix to ignore Makefiles when not present
# https://www.gnu.org/software/make/manual/html_node/Include.html
-include $(MAKEFILES)

ifneq ($(MAKEFILES),)
$(info [$(YELLOW)*$(NORMAL)] Use ``make menu`` for available targets)
$(info [$(YELLOW)*$(NORMAL)] Including available Makefiles: $(MAKEFILES))
$(info --)
else
$(warning Makefile includes directory not present: $(INCLUDE_DIR))
endif

VERSION?=$(shell grep '^version: ' plugin.spec.yaml | sed 's/version: //')
NAME?=$(shell grep '^name: ' plugin.spec.yaml | sed 's/name: //')
VENDOR?=$(shell grep '^vendor: ' plugin.spec.yaml | sed 's/vendor: //')
CWD?=$(shell basename $(PWD))
_NAME?=$(shell echo $(NAME) | awk '{ print toupper(substr($$0,1,1)) tolower(substr($$0,2)) }')
PKG=$(VENDOR)-$(NAME)-$(VERSION).tar.gz

# Set default target explicitly. Make's default behavior is the first target in the Makefile.
# We don't want that behavior due to includes which are read first
.DEFAULT_GOAL := default # Make >= v3.80 (make -version)


default: image tarball

tarball:
$(info [$(YELLOW)*$(NORMAL)] Creating plugin tarball)
rm -rf build
rm -rf $(PKG)
tar -cvzf $(PKG) --exclude=$(PKG) --exclude=tests --exclude=run.sh *

image:
$(info [$(YELLOW)*$(NORMAL)] Building plugin image)
docker build --pull -t $(VENDOR)/$(NAME):$(VERSION) .
docker tag $(VENDOR)/$(NAME):$(VERSION) $(VENDOR)/$(NAME):latest

regenerate:
$(info [$(YELLOW)*$(NORMAL)] Refreshing schema from plugin.spec.yaml)
insight-plugin refresh

export: image
$(info [$(YELLOW)*$(NORMAL)] Exporting docker image)
@printf "\n ---> Exporting Docker image to ./$(VENDOR)_$(NAME)_$(VERSION).tar\n"
@docker save $(VENDOR)/$(NAME):$(VERSION) | gzip > $(VENDOR)_$(NAME)_$(VERSION).tar

# Make will not run a target if a file of the same name exists unless setting phony targets
# https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html
.PHONY: default tarball image regenerate
46 changes: 46 additions & 0 deletions plugins/velociraptor_legacy/bin/icon_velociraptor_legacy
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#!/usr/bin/env python
# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT
import os
import json
from sys import argv

Name = "Velociraptor Legacy"
Vendor = "jbauvinet"
Version = "1.0.0"
Description = "Velociraptor is a unique, advanced open-source endpoint monitoring, digital forensic and cyber response platform. It provides you with the ability to more effectively respond to a wide range of digital forensic and cyber incident response investigations and data breaches"


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 icon_velociraptor_legacy import connection, actions, triggers, tasks

class ICONVelociraptorLegacy(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.Run())


"""Run plugin"""
cli = insightconnect_plugin_runtime.CLI(ICONVelociraptorLegacy())
cli.run()


if __name__ == "__main__":
main()
Binary file added plugins/velociraptor_legacy/extension.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
122 changes: 122 additions & 0 deletions plugins/velociraptor_legacy/help.md

Large diffs are not rendered by default.

Binary file added plugins/velociraptor_legacy/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT

from .run.action import Run

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT
from .action import Run
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import json
import paramiko
import base64
import grpc
import io
import time
from pyvelociraptor import api_pb2
from pyvelociraptor import api_pb2_grpc
import insightconnect_plugin_runtime
from .schema import RunInput, RunOutput, Input, Output, Component
# Custom imports below


class Run(insightconnect_plugin_runtime.Action):

def __init__(self):
super(self.__class__, self).__init__(
name="run",
description=Component.DESCRIPTION,
input=RunInput(),
output=RunOutput())

def run(self, params={}):
# START INPUT BINDING - DO NOT REMOVE - ANY INPUTS BELOW WILL UPDATE WITH YOUR PLUGIN SPEC AFTER REGENERATION
# END INPUT BINDING - DO NOT REMOVE
# TODO - If input bindings for connection can be done check to same if it you can do the same here
"""Runs a VQL query against the Velociraptor server.
Args:
config: A dictionary containing the configuration parameters for the Velociraptor server.
query: The VQL query to run.
Returns:
A tuple containing the query, the response, and the query execution logs.
"""
results = {}
try:
# Fill in the SSL params from the api_client config file. You can get such a file:
# velociraptor --config server.config.yaml config api_client > api_client.conf.yaml
api_connection_string = self.connection.api_connection_string
root_certificates_decoded = self.connection.root_certificates_decoded
private_key_decoded = self.connection.private_key_decoded
certificate_chain_decoded = self.connection.certificate_chain_decoded
query = params.get(Input.COMMAND)
creds = grpc.ssl_channel_credentials(
root_certificates = root_certificates_decoded,
private_key = private_key_decoded,
certificate_chain = certificate_chain_decoded)
# This option is required to connect to the grpc server by IP - we
# use self signed certs.
options = (('grpc.ssl_target_name_override', "VelociraptorServer",),)
# The first step is to open a gRPC channel to the server..
with grpc.secure_channel(api_connection_string,
creds, options) as channel:
stub = api_pb2_grpc.APIStub(channel)
# The request consists of one or more VQL queries. Note that you can collect artifacts by simply naming them using the
# "Artifact" plugin.
request = api_pb2.VQLCollectorArgs(
max_wait=1,
max_row=100,
Query=[api_pb2.VQLRequest(
Name="ICON Plugin Request",
VQL=query,
)],
)
# This will block as responses are streamed from the
# server. If the query is an event query we will run this loop
# forever.
logs_list = []
for response in stub.Query(request):
if response.Response:
package = json.loads(response.Response)
logs_list.append(package)

elif response.log:
# Query execution logs are sent in their own messages.
package = time.ctime(response.timestamp / 1000000), response.log
self.logger.info("Command Sent")
results["logs_list"] = logs_list[0]
return {Output.RESULTS: results}
except grpc.RpcError as e:
self.logger.info("Error: ",e)
results["logs_list"] = e
return {Output.RESULTS: results}

Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT
import insightconnect_plugin_runtime
import json


class Component:
DESCRIPTION = "Run Velociraptor command"


class Input:
COMMAND = "command"


class Output:
RESULTS = "results"


class RunInput(insightconnect_plugin_runtime.Input):
schema = json.loads(r"""
{
"type": "object",
"title": "Variables",
"properties": {
"command": {
"type": "string",
"description": "Command to execute on Velociraptor host",
"order": 1
}
},
"required": [
"command"
],
"definitions": {}
}
""")

def __init__(self):
super(self.__class__, self).__init__(self.schema)


class RunOutput(insightconnect_plugin_runtime.Output):
schema = json.loads(r"""
{
"type": "object",
"title": "Variables",
"properties": {
"results": {
"$ref": "#/definitions/results",
"title": "Results",
"description": "Results",
"order": 1
}
},
"required": [
"results"
],
"definitions": {
"results": {
"type": "object",
"title": "results",
"properties": {
"logs_list": {
"type": "array",
"title": "LOGS_LIST",
"description": "Logs List",
"items": {
"type": "object"
},
"order": 1
}
}
}
}
}
""")

def __init__(self):
super(self.__class__, self).__init__(self.schema)
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT
from .connection import Connection
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import json
import paramiko
import base64
import grpc
import io
import time
from pyvelociraptor import api_pb2
from pyvelociraptor import api_pb2_grpc
import insightconnect_plugin_runtime
from .schema import ConnectionSchema, Input
# Custom imports below


class Connection(insightconnect_plugin_runtime.Connection):

def __init__(self):
super(self.__class__, self).__init__(input=ConnectionSchema())

def connect(self, params):
# START INPUT BINDING - DO NOT REMOVE - ANY INPUTS BELOW WILL UPDATE WITH YOUR PLUGIN SPEC AFTER REGENERATION
# TODO: generate bound input variables for the user, to help handhold the user
# TODO: ex. self.api_key = params.get(Input.API_KEY)
# END INPUT BINDING - DO NOT REMOVE
self.logger.info("Connect: Connecting...")
"""Runs a VQL query against the Velociraptor server.
Args:
config: A dictionary containing the configuration parameters for the Velociraptor server.
query: The VQL query to run.
Returns:
A tuple containing the query, the response, and the query execution logs.
"""

try:
# Fill in the SSL params from the api_client config file. You can get such a file:
# velociraptor --config server.config.yaml config api_client > api_client.conf.yaml
api_connection_string = self.parameters["api_connection_string"]
root_certificates_decoded = base64.b64decode(self.parameters["ca_certificate"]["secretKey"])
private_key_decoded = base64.b64decode(self.parameters["client_private_key"]["secretKey"])
certificate_chain_decoded = base64.b64decode(self.parameters["client_cert"]["secretKey"])
query = "SELECT * FROM info()"
creds = grpc.ssl_channel_credentials(
root_certificates = root_certificates_decoded,
private_key = private_key_decoded,
certificate_chain = certificate_chain_decoded)
# This option is required to connect to the grpc server by IP - we
# use self signed certs.
options = (('grpc.ssl_target_name_override', "VelociraptorServer",),)
# The first step is to open a gRPC channel to the server..
with grpc.secure_channel(api_connection_string,
creds, options) as channel:
stub = api_pb2_grpc.APIStub(channel)

# The request consists of one or more VQL queries. Note that
# you can collect artifacts by simply naming them using the
# "Artifact" plugin.
request = api_pb2.VQLCollectorArgs(
max_wait=1,
max_row=100,
Query=[api_pb2.VQLRequest(
Name="ICON Plugin Request",
VQL=query,
)],
)
# This will block as responses are streamed from the
# server. If the query is an event query we will run this loop
# forever.
logs_list = []
for response in stub.Query(request):
if response.Response:
package = json.loads(response.Response)
logs_list.append(package)

elif response.log:
# Query execution logs are sent in their own messages.
package = time.ctime(response.timestamp / 1000000), response.log
self.logger.info("Connection Successful")
self.api_connection_string = self.parameters["api_connection_string"]
self.root_certificates_decoded = base64.b64decode(self.parameters["ca_certificate"]["secretKey"])
self.private_key_decoded = base64.b64decode(self.parameters["client_private_key"]["secretKey"])
self.certificate_chain_decoded = base64.b64decode(self.parameters["client_cert"]["secretKey"])
self.username = self.parameters["username"]
except grpc.RpcError as e:
self.logger.info("Error: ",e)
self.api_connection_string = self.parameters["api_connection_string"]
self.root_certificates_decoded = base64.b64decode(self.parameters["ca_certificate"]["secretKey"])
self.private_key_decoded = base64.b64decode(self.parameters["client_private_key"]["secretKey"])
self.certificate_chain_decoded = base64.b64decode(self.parameters["client_cert"]["secretKey"])
self.username = self.parameters["username"]
Loading

0 comments on commit f93d668

Please sign in to comment.