Skip to content

Commit

Permalink
Usage Examples (#116)
Browse files Browse the repository at this point in the history
* Update label_request.yml

Labeller fails on forks, removing workflow from dev branches.

* Sample code: Sample Uploads API

* Code sample: Sample Uploads API

* Sample config.json file

* Documentation updates

* Documentation updates

* Documentation updates

* Documentation updates

* Documentation updates

* Documentation updates

* Documentation updates

* Documentation updates

* Documentation updates

* Documentation updates

* Uploading simple example of containing and uncontaining a host via API

* Documentation updates

* Documentation updates

* Documentation updates

* Update labeler.yml

Added code samples label tagging

* Update labeler.yml

* Update wordlist.txt

* Linting

* Update linting.yml

* Sample Uploads sample adjustments

* Update bandit.yml

Co-authored-by: Shane Shellenbarger <[email protected]>
  • Loading branch information
jshcodes and Shane Shellenbarger authored Apr 3, 2021
1 parent 1b79f0c commit 69ed0bc
Show file tree
Hide file tree
Showing 10 changed files with 262 additions and 4 deletions.
10 changes: 9 additions & 1 deletion .github/labeler.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
documentation:
- any: ['docs/*', '*.md']
- docs/*
- '*.md'
- src/falconpy/*.md
- samples/*.md

package:
- src/*.py
Expand All @@ -13,3 +16,8 @@ pipeline:

unit testing:
- any: ['tests/*', 'util/*']

code samples:
- samples/*.py
- samples/real_time_response/*.py
- samples/sample_uploads/*.py
1 change: 1 addition & 0 deletions .github/wordlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ autogenerated
pytest
ipython
dev
config
cov
FalconDebug
Uber
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/bandit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ jobs:
python -m pip install --upgrade pip
python -m pip install bandit
pip install -r requirements.txt
- name: Analyze with bandit
- name: Analyze package with bandit
run: |
bandit -r src
- name: Analyze samples with bandit
run: |
bandit -r samples
1 change: 0 additions & 1 deletion .github/workflows/label_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ on:
pull_request:
branches:
- main
- 'ver_*'

jobs:
triage:
Expand Down
8 changes: 7 additions & 1 deletion .github/workflows/linting.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,16 @@ jobs:
python -m pip install --upgrade pip
python -m pip install flake8
pip install -r requirements.txt
- name: Lint with flake8
- name: Lint package source with flake8
run: |
# stop the build if there are Python syntax errors or undefined names
flake8 src/falconpy --count --select=E9,F63,F7,F82 --show-source --statistics
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
# Stop the build on all linting errors - 04.02.21 / jshcodes@CrowdStrike
flake8 src/falconpy --count --max-complexity=15 --max-line-length=127 --statistics
- name: Lint samples with flake8
run: |
# stop the build if there are Python syntax errors or undefined names
flake8 samples --count --select=E9,F63,F7,F82 --show-source --statistics
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
flake8 samples --exit-zero --count --max-complexity=15 --max-line-length=127 --statistics
51 changes: 51 additions & 0 deletions samples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
![CrowdStrike Falcon](https://raw.githubusercontent.com/CrowdStrike/falconpy/main/docs/asset/cs-logo.png)

[![Twitter URL](https://img.shields.io/twitter/url?label=Follow%20%40CrowdStrike&style=social&url=https%3A%2F%2Ftwitter.com%2FCrowdStrike)](https://twitter.com/CrowdStrike)

# FalconPy usage examples
These examples are provided as a quick start for your project.

+ [Authentication for Examples](#authentication-for-these-examples)
+ [Samples by API service collection](#samples-by-api-service-collection)
- [Detections](#detections)
- [Event Streams](#event-streams)
- [Falcon Discover](#falcon-discover)
- [Hosts](#hosts)
- [Real Time Response](#real-time-response)
- [Sample Uploads](#sample-uploads)
+ [Suggestions](#suggestions)

## Authentication for these Examples
In order to expedite sample delivery, we will be following a standard pattern for defining and providing credentials to the API.
This is not the only method of providing these values, and not recommended for production deployments as the config.json file is
**not encrypted**.

In order to test these samples locally in your development environment, rename the file `config_sample.json` to `config.json` and then
update this file to reflect your current development API credentials.

## Samples by API service collection
These samples are categorized by API service collection. The list below will grow as more samples are planned.

### Detections
_Coming Soon_

### Event Streams
_Coming Soon_

### Falcon Discover
_Coming Soon_

### Hosts
_Coming Soon_

### Real Time Response
+ [Quarantine a host](real_time_response/quarantine_hosts.py)

### Sample Uploads
+ [Upload, Retrieve and then Delete a file (Service Class)](sample_uploads/sample_uploads_service.py)
+ [Upload, Retrieve and then Delete a file (Uber Class)](sample_uploads/sample_uploads_uber.py)

## Suggestions
Got a suggestion for an example you'd like to see? Let us know by posting a message to our [discussion board](https://github.com/CrowdStrike/falconpy/discussions).

Have an example you've developed yourself that you'd like to share? **_Excellent!_** Please review our [contributing guidelines](/CONTRIBUTING.md) and then submit a pull request.
4 changes: 4 additions & 0 deletions samples/config_sample.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"falcon_client_id": "API ID GOES HERE",
"falcon_client_secret": "API SECRET GOES HERE"
}
91 changes: 91 additions & 0 deletions samples/real_time_response/quarantine_hosts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# ____ _ _____ _ ____
# | _ \ ___ __ _| | |_ _(_)_ __ ___ ___ | _ \ ___ ___ _ __ ___ _ __ ___ ___
# | |_) / _ \/ _` | | | | | | '_ ` _ \ / _ \ | |_) / _ \/ __| '_ \ / _ \| '_ \/ __|/ _ \
# | _ < __/ (_| | | | | | | | | | | | __/ | _ < __/\__ \ |_) | (_) | | | \__ \ __/
# |_| \_\___|\__,_|_| |_| |_|_| |_| |_|\___| |_| \_\___||___/ .__/ \___/|_| |_|___/\___|
# |_|
#
# This example demonstrates how to apply or lift containment on a host using its hostname.
# This solution makes use of Service Class legacy authentication.
#
import json
import argparse
# Import necessary FalconPy classes
from falconpy import oauth2 as FalconAuth
from falconpy import hosts as FalconHosts

# Setup our argument parser
parser = argparse.ArgumentParser("Script that leverages Falcon API to (un)contain hosts")
parser.add_argument('-c', '--creds_file', dest='creds_file', help='Path to creds json file', required=True)
parser.add_argument('-H', '--hostname', dest='hostname', help='Hostname to quarantine', required=True)
parser.add_argument('-l', '--lift', dest='lift_containment', action="store_true", help='Lift containment', default=False)
# Parse our ingested arguments
args = parser.parse_args()
# Hostname of the machine to contain / release
hostname = args.hostname
# Default action is to quarantine
if args.lift_containment:
action = "lift_containment"
else:
action = "contain"
# Use the credentials file provided
creds_file = args.creds_file
# Load the contents of the creds file into the creds dictionary
with open(creds_file) as f:
creds = json.load(f)
# Create an instance of our OAuth2 authorization class using our ingested creds
authorization = FalconAuth.OAuth2(creds={
"client_id": creds['falcon_client_id'],
"client_secret": creds['falcon_client_secret']
})
# Try to generate a token
try:
token = authorization.token()['body']['access_token']
except Exception as e:
# Exit out on authentication errors
print("Failed to authenticate")
print(e)
exit(-1)
# If we have a token, proceed to the next step
if token:
# Create an instance of the Hosts class
falcon = FalconHosts.Hosts(access_token=token)
# Create our parameter payload, using our ingested hostname as a filter
PARAMS = {
'offset': 0,
'limit': 10,
'filter': f"hostname:'{hostname}'"
}
# Query the Hosts API for hosts that match our filter pattern
response = falcon.QueryDevicesByFilter(parameters=PARAMS)
# Retrieve the list of IDs returned
contain_ids = response['body']['resources']
# Output the result
print(json.dumps(response, indent=4))

if not contain_ids:
# No hosts were found, exit out
print(f"[-] Could not find hostname: {hostname} - Please verify proper case")
exit(-2)

# Create our next payload based upon the action requested
PARAMS = {
'action_name': action
}
# Our body payload will contain our list of IDs
BODY = {
'ids': contain_ids
}
# Provide a status update to the terminal
if action == "contain":
print(f"\n[+] Containing: {hostname}\n")
else:
print(f"\n[+] Lifting Containment: {hostname}\n")

# Perform the requested action
# TODO: Get rid of action_name="contain" once bug is resolved
# BUG: https://github.com/CrowdStrike/falconpy/issues/114
response = falcon.PerformActionV2(parameters=PARAMS, body=BODY,
action_name="contain")
# Output the result
print(json.dumps(response, indent=4))
48 changes: 48 additions & 0 deletions samples/sample_uploads/sample_uploads_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# ____ _ _ _ _ _
# / ___| __ _ _ __ ___ _ __ | | ___ | | | |_ __ | | ___ __ _ __| |___
# \___ \ / _` | '_ ` _ \| '_ \| |/ _ \ | | | | '_ \| |/ _ \ / _` |/ _` / __|
# ___) | (_| | | | | | | |_) | | __/ | |_| | |_) | | (_) | (_| | (_| \__ \
# |____/ \__,_|_| |_| |_| .__/|_|\___| \___/| .__/|_|\___/ \__,_|\__,_|___/
# |_| |_|
#
# ____ _ ____ _
# / ___| ___ _ ____ _(_) ___ ___ / ___| | __ _ ___ ___
# \___ \ / _ \ '__\ \ / / |/ __/ _ \ | | | |/ _` / __/ __|
# ___) | __/ | \ V /| | (_| __/ | |___| | (_| \__ \__ \
# |____/ \___|_| \_/ |_|\___\___| \____|_|\__,_|___/___/
#
#
# These examples show how to interact with the Sample Uploads API using the Service Class
# This example uses Credential authentication and supports token refresh / authentication free usage.
#
import json
# Import the Sample Uploads service class
from falconpy import sample_uploads as FalconUploads

# #Grab our config parameters
with open('config.json', 'r') as file_config:
config = json.loads(file_config.read())

falcon = FalconUploads.Sample_Uploads(creds={
"client_id": config["falcon_client_id"],
"client_secret": config["falcon_client_secret"]
}
)

# Define our file
FILENAME = "testfile.jpg"
# Open the file for binary read, this will be our payload
PAYLOAD = open(FILENAME, 'rb').read()
# Upload the file using the Sample Uploads API, name this file "newfile.jpg" in the API
# Since we are using the Service Class, we do not need to specify the content type
response = falcon.UploadSampleV3(file_name="newfile.jpg", file_data=PAYLOAD)
# Grab the SHA256 unique identifier for the file we just uploaded
sha = response["body"]["resources"][0]["sha256"]
# Download a copy of this file, use the SHA256 ID to retrieve it
response = falcon.GetSampleV3(ids=sha)
# Save the result to a new file
open('serviceclass.jpg', 'wb').write(response)
# Delete the file from the API
response = falcon.DeleteSampleV3(ids=sha)
# Print the results of our delete command
print(json.dumps(response, indent=4))
47 changes: 47 additions & 0 deletions samples/sample_uploads/sample_uploads_uber.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# ____ _ _ _ _ _
# / ___| __ _ _ __ ___ _ __ | | ___ | | | |_ __ | | ___ __ _ __| |___
# \___ \ / _` | '_ ` _ \| '_ \| |/ _ \ | | | | '_ \| |/ _ \ / _` |/ _` / __|
# ___) | (_| | | | | | | |_) | | __/ | |_| | |_) | | (_) | (_| | (_| \__ \
# |____/ \__,_|_| |_| |_| .__/|_|\___| \___/| .__/|_|\___/ \__,_|\__,_|___/
# |_| |_|
#
#
# _ _ _ ____ _
# | | | | |__ ___ _ __ / ___| | __ _ ___ ___
# | | | | '_ \ / _ \ '__| | | | |/ _` / __/ __|
# | |_| | |_) | __/ | | |___| | (_| \__ \__ \
# \___/|_.__/ \___|_| \____|_|\__,_|___/___/
#
# These examples show how to interact with the Sample Uploads API using the Uber class.
#
import json
# Import the Uber Class
from falconpy import api_complete as FalconSDK

# Grab our config parameters
with open('../config.json', 'r') as file_config:
config = json.loads(file_config.read())

# Create an instance of the Uber class
falcon = FalconSDK.APIHarness(creds={
"client_id": config["falcon_client_id"],
"client_secret": config["falcon_client_secret"]
}
)

# Define our file
FILENAME = "testfile.jpg"
# Open the file for binary read, this will be our payload
PAYLOAD = open(FILENAME, 'rb').read()
# Upload the file using the Sample Uploads API, name this file "newfile.jpg" in the API
response = falcon.command('UploadSampleV3', file_name="newfile.jpg", data=PAYLOAD, content_type="application/octet-stream")
# Grab the SHA256 unique identifier for the file we just uploaded
sha = response["body"]["resources"][0]["sha256"]
# Download a copy of this file, use the SHA256 ID to retrieve it
response = falcon.command("GetSampleV3", ids=sha)
# Save the result to a new file
open('uberclass.jpg', 'wb').write(response)
# Delete the file from the API
response = falcon.command("DeleteSampleV3", ids=sha)
# Print the results of our delete command
print(json.dumps(response, indent=4))

0 comments on commit 69ed0bc

Please sign in to comment.