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
19 changes: 19 additions & 0 deletions bin/pwnboard/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# PWNBoard Integration

This script is meant to use the Tavern GraphQL API to periodially update a PWNBoard instance with host access.

## Usage

Set your `auth-session` cookie from the tavern app to the environment variable `TAVERN_AUTH_SESSION`

`python3 main.py https://tavern.yourdomain.here https://pwnboard.yourdomain.here`

**Note**: Routes will be appended by program. Do not append `/graphql` and `/pwn/boxaccess` in the arguments.

Other flags:

`-i, --interval` - Set interval (in seconds) that the API will be queried. Default=5

`-t, --timediff` - Set max time (in seconds) since now that will be used to determine if a host is still responding. Default=5

`-n, --name` - Set name used for application on PWNBoard. Default="Realm"
107 changes: 107 additions & 0 deletions bin/pwnboard/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import requests
import os
import sys
import argparse
from time import sleep
from datetime import datetime, timedelta


def make_graphql_request(api_url, query, variables, cookies=None):
headers = {
"Content-Type": "application/json",
"Accept": "application/json",
}

data = {"query": query, "variables": variables}
response = requests.post(api_url, json=data, headers=headers, cookies=cookies)
if response.status_code == 200:
return response.json()
else:
print(f"Error {response.status_code}: {response.text}")
return None


def make_pwnboard_request(api_url, application_name, ips):
data = {"ip": ips[0], "application": application_name}
if len(ips) > 1:
data["ips"] = ips[1:]
response = requests.post(api_url, json=data)

if response.status_code == 202:
return True
else:
print(f"Error {response.status_code}: {response.text}")
return False


if __name__ == "__main__":
parser = argparse.ArgumentParser(
prog="Tavern PWNBoard Integration",
description="Queries GraphQL for active beacons to update PWNBoard",
)

parser.add_argument("tavern_url")

parser.add_argument("pwnboard_url")

parser.add_argument(
"-n", "--name", default="Realm", help="Custom Application Name on PWNBoard"
)
parser.add_argument(
"-i",
"--interval",
default=5,
help="Callback Interval to PWNBoard (seconds). Default to 5 seconds",
)
parser.add_argument(
"-t",
"--timediff",
default=5,
help="Number of seconds from now to check for a beacon response",
)

args = parser.parse_args()

auth_session = os.environ.get("TAVERN_AUTH_SESSION")

if auth_session is None:
print(
"No auth-session cookie found. Please set it using the environment variable TAVERN_AUTH_SESSION"
)
exit(1)

graphql_query = """
query pwnboard($input: HostWhereInput) {
hosts(where: $input) {
primaryIP
}
}
"""
cookies = {
"auth-session": auth_session,
}

graphql_url = f"{args.tavern_url}/graphql"

pwnboard_url = f"{args.pwnboard_url}/pwn/boxaccess"

while True:
current_time = datetime.utcnow()

time_five_minutes_ago = current_time - timedelta(seconds=args.timediff)

formatted_time = time_five_minutes_ago.strftime("%Y-%m-%dT%H:%M:%SZ")

graphql_variables = {"input": {"lastSeenAtGT": formatted_time}}

result = make_graphql_request(
graphql_url, graphql_query, graphql_variables, cookies
)

if result:
if result["data"] and len(result["data"]["hosts"]) > 0:
ips = list(map(lambda x: x["primaryIP"], result["data"]["hosts"]))
make_pwnboard_request(pwnboard_url, args.name, ips)
else:
print("No data found :(")
sleep(args.interval)