From 5de9d5dd7fa5ebfc2441cf19ebe9ef2c0b998b97 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Tue, 28 Jan 2025 21:53:10 -0500 Subject: [PATCH 1/3] Cred poster --- bin/ccdc-team-mappings/create_tags.py | 20 +--- bin/cred-publishing/creds.py | 147 ++++++++++++++++++++++++++ 2 files changed, 149 insertions(+), 18 deletions(-) create mode 100644 bin/cred-publishing/creds.py diff --git a/bin/ccdc-team-mappings/create_tags.py b/bin/ccdc-team-mappings/create_tags.py index 2512b270c..631d78282 100644 --- a/bin/ccdc-team-mappings/create_tags.py +++ b/bin/ccdc-team-mappings/create_tags.py @@ -90,22 +90,6 @@ def create_tag(self, tag_name: str, tag_kind: str): else: return res['data']['createTag']['id'] - def add_hosts(self, tag_id: str, hosts: list): - graphql_query = """ -mutation updateTag($input:UpdateTagInput!, $tagid:ID!){ - updateTag(input:$input, tagID:$tagid) { - id - } -} """ - print(hosts) - graphql_variables = {"input":{"addHostIDs":hosts},"tagid":tag_id} - res = self.make_graphql_request(graphql_query, graphql_variables) - if 'errors' in res: - pprint(res) - return -1 - else: - return res['data']['updateTag']['id'] - def run(self): service_map = { } data = self.get_hosts() @@ -153,5 +137,5 @@ def run(self): exit(1) graphql_url = f"{args.tavern_url}/graphql" - tagger = TagBuilder(graphql_url, auth_session) - tagger.run() \ No newline at end of file + poster = TagBuilder(graphql_url, auth_session) + poster.run() \ No newline at end of file diff --git a/bin/cred-publishing/creds.py b/bin/cred-publishing/creds.py new file mode 100644 index 000000000..09b58acbd --- /dev/null +++ b/bin/cred-publishing/creds.py @@ -0,0 +1,147 @@ +import argparse +import os +import re +import requests +from pprint import pprint +import json +from dataclasses import dataclass + + +@dataclass +class CredPost: + graphql_url: str + auth_session: str + known_hosts: dict + + def make_graphql_request(self, query, variables): + headers = { + "Content-Type": "application/json", + "Accept": "application/json", + } + + data = {"query": query, "variables": variables} + cookies = { + "auth-session": self.auth_session, + } + + response = requests.post(self.graphql_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 get_hosts(self, ip: str): + graphql_query = """ +query getHosts($where:HostWhereInput){ + hosts(where:$where) { + id + primaryIP + name + } +} """ + + graphql_variables = { + "where": { + "primaryIP": ip + } +} + res = self.make_graphql_request(graphql_query, graphql_variables) + if 'errors' in res: + return -1 + else: + return res + + def create_cred(self, principal: str, secret: str, kind: str, host_id: int): + graphql_query = """ +mutation CreateCreds($input:CreateHostCredentialInput!) { + createCredential(input:$input) { + principal + secret + kind + host { + id + } + task { + id + } + } +} +""" + graphql_variables = { + "input": { + "principal": principal, + "secret": secret, + "kind": kind, + "hostID": host_id + } +} + res = self.make_graphql_request(graphql_query, graphql_variables) + if 'errors' in res: + pprint(res) + return -1 + else: + return res['data']['createTag']['id'] + + def add_hosts(self, tag_id: str, hosts: list): + graphql_query = """ +mutation updateTag($input:UpdateTagInput!, $tagid:ID!){ + updateTag(input:$input, tagID:$tagid) { + id + } +} """ + print(hosts) + graphql_variables = {"input":{"addHostIDs":hosts},"tagid":tag_id} + res = self.make_graphql_request(graphql_query, graphql_variables) + if 'errors' in res: + pprint(res) + return -1 + else: + return res['data']['updateTag']['id'] + + def get_host_id(self, ip: str) -> int: + if ip in self.known_hosts: + return self.known_hosts[ip] + + self.known_hosts[ip] = self.get_hosts(ip) + return self.known_hosts[ip] + + def run(self, log_file): + with open(log_file) as file: + for line in file: + line_arr = line.strip().split(":") + ip = line_arr[0] + user = line_arr[1] + password = line_arr[2] + host_id = self.get_host_id(ip) + self.create_cred( + user, + password, + "KIND_PASSWORD", + host_id + ) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + prog="CCDC Cred post", + description="Parse cred logs in form `ip:user:password` and post them to tavern", + ) + + parser.add_argument("tavern_url") + parser.add_argument("log_file") + + 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_url = f"{args.tavern_url}/graphql".replace("//","/") + poster = CredPost(graphql_url, auth_session) + poster.run(args.log_file) \ No newline at end of file From 007a05062f8d4ca11386e17e0f6529bd27dfc87b Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Wed, 29 Jan 2025 03:07:48 +0000 Subject: [PATCH 2/3] Works with ip --- bin/cred-publishing/creds.py | 64 ++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 29 deletions(-) diff --git a/bin/cred-publishing/creds.py b/bin/cred-publishing/creds.py index 09b58acbd..f1e717f42 100644 --- a/bin/cred-publishing/creds.py +++ b/bin/cred-publishing/creds.py @@ -24,29 +24,27 @@ def make_graphql_request(self, query, variables): "auth-session": self.auth_session, } - response = requests.post(self.graphql_url, json=data, headers=headers, cookies=cookies) + response = requests.post( + self.graphql_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 get_hosts(self, ip: str): graphql_query = """ query getHosts($where:HostWhereInput){ hosts(where:$where) { id - primaryIP - name } } """ graphql_variables = { - "where": { - "primaryIP": ip - } -} + "where": { + "primaryIP": ip + } + } res = self.make_graphql_request(graphql_query, graphql_variables) if 'errors' in res: return -1 @@ -70,19 +68,23 @@ def create_cred(self, principal: str, secret: str, kind: str, host_id: int): } """ graphql_variables = { - "input": { - "principal": principal, - "secret": secret, - "kind": kind, - "hostID": host_id - } -} + "input": { + "principal": principal, + "secret": secret, + "kind": kind, + "hostID": host_id + } + } res = self.make_graphql_request(graphql_query, graphql_variables) + if res is None: + print("Error res is none") + return -1 if 'errors' in res: pprint(res) return -1 else: - return res['data']['createTag']['id'] + pprint(res) + return res['data']['createCredential']['host']['id'] def add_hosts(self, tag_id: str, hosts: list): graphql_query = """ @@ -92,7 +94,7 @@ def add_hosts(self, tag_id: str, hosts: list): } } """ print(hosts) - graphql_variables = {"input":{"addHostIDs":hosts},"tagid":tag_id} + graphql_variables = {"input": {"addHostIDs": hosts}, "tagid": tag_id} res = self.make_graphql_request(graphql_query, graphql_variables) if 'errors' in res: pprint(res) @@ -100,27 +102,31 @@ def add_hosts(self, tag_id: str, hosts: list): else: return res['data']['updateTag']['id'] - def get_host_id(self, ip: str) -> int: + def get_host_ids(self, ip: str) -> int: if ip in self.known_hosts: return self.known_hosts[ip] - self.known_hosts[ip] = self.get_hosts(ip) + res = self.get_hosts(ip) + + self.known_hosts[ip] = [host['id'] for host in res['data']['hosts']] + print(self.known_hosts[ip]) return self.known_hosts[ip] def run(self, log_file): with open(log_file) as file: for line in file: line_arr = line.strip().split(":") + print(line_arr) ip = line_arr[0] user = line_arr[1] password = line_arr[2] - host_id = self.get_host_id(ip) - self.create_cred( - user, - password, - "KIND_PASSWORD", - host_id - ) + for host_id in self.get_host_ids(ip): + self.create_cred( + user, + password, + "KIND_PASSWORD", + host_id + ) if __name__ == "__main__": @@ -142,6 +148,6 @@ def run(self, log_file): ) exit(1) - graphql_url = f"{args.tavern_url}/graphql".replace("//","/") - poster = CredPost(graphql_url, auth_session) - poster.run(args.log_file) \ No newline at end of file + graphql_url = f"{args.tavern_url}/graphql" + poster = CredPost(graphql_url, auth_session, {}) + poster.run(args.log_file) From f462cf8ca8881a54547fc993dd9bc85781bb92c9 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Wed, 29 Jan 2025 03:23:46 +0000 Subject: [PATCH 3/3] Add team option --- bin/cred-publishing/creds.py | 54 ++++++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 12 deletions(-) diff --git a/bin/cred-publishing/creds.py b/bin/cred-publishing/creds.py index f1e717f42..4efbb16b1 100644 --- a/bin/cred-publishing/creds.py +++ b/bin/cred-publishing/creds.py @@ -32,7 +32,7 @@ def make_graphql_request(self, query, variables): print(f"Error {response.status_code}: {response.text}") return None - def get_hosts(self, ip: str): + def get_host_ids_by_ip(self, ip: str): graphql_query = """ query getHosts($where:HostWhereInput){ hosts(where:$where) { @@ -51,7 +51,29 @@ def get_hosts(self, ip: str): else: return res + def get_host_ids_by_group(self, group: str): + graphql_query = """ +query getHosts($where:HostWhereInput){ + hosts(where:$where) { + id + } +} """ + + graphql_variables = { + "where": { + "hasTagsWith": { + "name": group + } + } + } + res = self.make_graphql_request(graphql_query, graphql_variables) + if 'errors' in res: + return -1 + else: + return res + def create_cred(self, principal: str, secret: str, kind: str, host_id: int): + print(host_id) graphql_query = """ mutation CreateCreds($input:CreateHostCredentialInput!) { createCredential(input:$input) { @@ -102,25 +124,30 @@ def add_hosts(self, tag_id: str, hosts: list): else: return res['data']['updateTag']['id'] - def get_host_ids(self, ip: str) -> int: - if ip in self.known_hosts: - return self.known_hosts[ip] + def get_host_ids(self, team: str, selector: str) -> int: + if selector in self.known_hosts: + print("Cached") + return self.known_hosts[selector] - res = self.get_hosts(ip) + res = {} + if not team: + res = self.get_host_ids_by_ip(selector) + else: + res = self.get_host_ids_by_group(selector) - self.known_hosts[ip] = [host['id'] for host in res['data']['hosts']] - print(self.known_hosts[ip]) - return self.known_hosts[ip] + self.known_hosts[selector] = [host['id'] + for host in res['data']['hosts']] + return self.known_hosts[selector] - def run(self, log_file): + def run(self, team: bool, log_file: str): with open(log_file) as file: for line in file: line_arr = line.strip().split(":") print(line_arr) - ip = line_arr[0] + unique = line_arr[0] user = line_arr[1] password = line_arr[2] - for host_id in self.get_host_ids(ip): + for host_id in self.get_host_ids(team, unique): self.create_cred( user, password, @@ -137,6 +164,9 @@ def run(self, log_file): parser.add_argument("tavern_url") parser.add_argument("log_file") + parser.add_argument("--team", + action=argparse.BooleanOptionalAction, + help="Switch to use team number instead of IP address `team01:username:password`") args = parser.parse_args() @@ -150,4 +180,4 @@ def run(self, log_file): graphql_url = f"{args.tavern_url}/graphql" poster = CredPost(graphql_url, auth_session, {}) - poster.run(args.log_file) + poster.run(args.team, args.log_file)