This repository was archived by the owner on Aug 28, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathhackerone2threadfix.py
More file actions
211 lines (183 loc) · 6.31 KB
/
hackerone2threadfix.py
File metadata and controls
211 lines (183 loc) · 6.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
#!/usr/bin/env python3
import os
import sys
import pandas
import requests
import argparse
import json
from datetime import datetime
## Usage
parser = argparse.ArgumentParser(
description="""Script that enables a quick, API-based export from HackerOne to a compatible .csv format for fast upload to ThreadFix."""
)
parser.add_argument("h1_program_handle", help="your HackerOne program handle")
args = parser.parse_args()
## Variables
# API variables
headers = {"Accept": "application/json"}
url = "https://api.hackerone.com/v1/"
# get H1 API creds from OS variables and check if they're filled
user = os.environ.get("H1_IDENTIFIER")
if user == None:
exit("Please ensure your 'H1_IDENTIFIER' environment variable is set correctly.")
token = os.environ.get("H1_TOKEN")
if token == None:
exit("Please ensure your 'H1_TOKEN' environment variable is set correctly.")
program = os.environ.get("H1_PROGRAM")
## Functions
def json_extract(obj, key):
"""
Recursively fetch values from nested JSON.
"""
arr = []
def extract(obj, arr, key):
"""Recursively search for values of key in JSON tree."""
if isinstance(obj, dict):
for k, v in obj.items():
if isinstance(v, (dict, list)):
extract(v, arr, key)
elif k == key:
arr.append(v)
elif isinstance(obj, list):
for item in obj:
extract(item, arr, key)
return arr
values = extract(obj, arr, key)
return values
def query_api():
"""
This function queries the HackerOne API for all reports in a given program
"""
global response
raw = requests.get(
"https://api.hackerone.com/v1/reports/",
auth=(user, token),
# ADD CUSTOM PARAMETERS AND FILTERS HERE: https://api.hackerone.com/customer-resources/?python#reports-get-all-reports
params={
"filter[program][]": [sys.argv[1]],
"page[size]": 100,
},
headers=headers,
)
# Check authentication & authorization
if raw.status_code == 404:
print("\nThe H1 API returned no data.\n")
print(
"There may be an issue with your authentication or authorization. Please check that your H1 API identifier, API token, program handle, and program permissions are all correct.\n"
)
print(
"Helpful references:\n- https://api.hackerone.com\n- https://docs.hackerone.com"
)
exit()
raw = raw.json() # convert json to raw
response = raw["data"] # strip data
# H1 API is paginated, capped at 100 reports per call. Iterate until all reports are found
while "next" in raw["links"]:
raw = requests.get(
raw["links"]["next"],
auth=(user, token),
headers=headers,
).json()
response.extend(raw["data"])
def create_csv():
"""
This function creates the CSV file from the API response
"""
# create dataframe
df = pandas.DataFrame()
# Report IDs - data.id
id_list = [response[id]["id"] for id in range(len(response))]
print("\nTotal number of H1 reports found: " + str(len(id_list)) + "\n")
# add to dataframe
df["NativeID"] = id_list
# Weaknesses - data.relationships.weakness.data.attributes.external_id
cwe_list = []
for id in range(len(id_list)):
temp = response[id]["relationships"]
temp2 = "".join(json_extract(temp, "external_id"))
cwe_list.append(temp2[4:])
# add to dataframe
df["CWE"] = cwe_list
# Severities - data.relationships.severity.data.attributes.rating
sev_list = []
for id in range(len(id_list)):
temp = response[id]["relationships"]
temp2 = "".join(json_extract(temp, "rating"))
sev_list.append(temp2)
# add to dataframe
df["Severity"] = sev_list
# Report Title - data.attributes.title
title_list = []
for id in range(len(id_list)):
temp = response[id]["attributes"]
temp2 = "".join(json_extract(temp, "title"))
title_list.append(temp2)
# add to dataframe
df["ShortDescription"] = title_list
# Report Body - data.attributes.vulnerability_information
body_list = []
for id in range(len(id_list)):
temp = response[id]["attributes"]
temp2 = "".join(json_extract(temp, "vulnerability_information"))
body_list.append(temp2)
# add to dataframe
df["LongDescription"] = body_list
# Date - data.attributes.created_at - 2021-04-07T17:34:57.748Z
date_list = []
for id in range(len(id_list)):
temp = response[id]["attributes"]
temp2 = "".join(json_extract(temp, "created_at"))
temp3 = temp2[:10]
date = datetime.strptime(temp3, "%Y-%m-%d")
date = date.strftime("%d/%m/%Y")
date_list.append(date)
# add to dataframe
df["Date"] = date_list
# Individual Report URLs
url_list = []
for i in range(len(id_list)):
temp = "https://hackerone.com/reports/" + id_list[i]
url_list.append(temp)
# add to dataframe
df["url"] = url_list
# add columns to dataframe
df.insert(0, "LineText", "")
df.insert(0, "ColumnNumber", 1)
df.insert(0, "LineNumber", 1)
df.insert(0, "SourceFileName", "")
df.insert(0, "IssueID", "")
df.insert(0, "parameter", "")
df.insert(0, "Source", "HackerOne")
# fix severity values
df.replace(to_replace="critical", value="Critical", inplace=True)
df.replace(to_replace="high", value="High", inplace=True)
df.replace(to_replace="medium", value="Medium", inplace=True)
df.replace(to_replace="low", value="Low", inplace=True)
df.replace(to_replace="none", value="Info", inplace=True)
# reorder columns
df = df[
[
"Severity",
"CWE",
"Source",
"url",
"parameter",
"NativeID",
"ShortDescription",
"LongDescription",
"IssueID",
"Date",
"SourceFileName",
"LineNumber",
"ColumnNumber",
"LineText",
]
]
# write file
df.to_csv("h1-export.csv", index=False)
print("Here's a 10 row preview of the ThreadFix .csv file:\n")
print(df.head(10)[["Severity", "CWE", "ShortDescription", "Date"]])
## Main
if __name__ == "__main__":
query_api()
create_csv()