Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Usage Examples #116

Merged
merged 26 commits into from
Apr 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
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: 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))