-
Notifications
You must be signed in to change notification settings - Fork 6
/
create_demo.py
402 lines (338 loc) · 12.6 KB
/
create_demo.py
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
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
from faker import Faker
from aiosmtpd.handlers import Sink
from aiosmtpd.controller import Controller
from os import sys
from gophish import Gophish
from gophish.models import *
import random
import requests
import urllib3
import time
import argparse
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
faker = Faker()
DEFAULT_USER_AGENT = 'Gophish Test Data Generator'
DEFAULT_TEMPLATE_HTML = '''<html>
<head></head>
<body>
<p>{{.FirstName}},</p>
<p>Please click <a href="{{.URL}}">this link</a> to reset your
password.</p>
{{.Tracker}}
</body>
</html>
'''
DEFAULT_TEMPLATE_TEXT = 'Default template text'
DEFAULT_LANDING_PAGE_HTML = '''<html>
<head></head>
<body>
Please sign in below
<form action="" method="POST">
<input name="username" type="text" placeholder="username"/>
<input name="password" type="password"/>
</form>
</body>
</html>
'''
def generate_groups(api, num_groups=10, num_members=100):
"""Generates groups with randomly created targets using the Gophish API
Each target has a randomly generated first and last name. The email address
for the target is in [email protected] format.
This returns the names of the created groups, *not* the full Group objects
to save memory.
Arguments:
api {gophish.API} -- The authenticated Gophish API client
Keyword Arguments:
num_groups {int} -- [description] (default: {10})
num_members {int} -- [description] (default: {100})
"""
group_names = []
for group_idx in range(0, num_groups):
targets = []
for target_idx in range(0, num_members):
first_name = faker.first_name()
last_name = faker.last_name()
email = '{}.{}@example.com'.format(first_name, last_name)
targets.append(
User(first_name=first_name, last_name=last_name, email=email))
group = Group(name='Test Group {}'.format(group_idx), targets=targets)
try:
group = api.groups.post(group)
except Exception as e:
print('Unable to post group: {}'.format(e))
break
group_names.append(group.name)
return group_names
def generate_sending_profile(api, host):
"""Generates a new sending profile
Arguments:
api {gophish.API} -- The authenticated Gophish API client
host {str} -- The host:port for the SMTP server
Returns:
gophish.models.SMTP -- The created sending profile
"""
sending_profile = SMTP(
name='Test Sending Profile',
host=host,
from_address='Example Sender <[email protected]>')
try:
sending_profile = api.smtp.post(sending_profile)
except Exception as e:
print('Unable to create sending profile: {}'.format(e))
return sending_profile
def generate_template(api,
text=DEFAULT_TEMPLATE_TEXT,
html=DEFAULT_TEMPLATE_HTML):
"""Creates a new email template
Arguments:
api {gophish.API} -- The authenticated Gophish API client
Keyword Arguments:
text {str} -- The email template text (default: {DEFAULT_TEMPLATE_TEXT})
html {str} -- The email template HTML (default: {DEFAULT_TEMPLATE_HTML})
Returns:
gophish.models.Template -- The created template
"""
template = Template(name='Example Template', text=text, html=html)
try:
template = api.templates.post(template)
except Exception as e:
print('Unable to create template: {}'.format(e))
return template
def generate_landing_page(api, html=DEFAULT_LANDING_PAGE_HTML):
"""Generates a new landing page.
Arguments:
api {gophish.API} -- The authenticated Gophish API client
Keyword Arguments:
html {str} -- The landing page HTML (default: {DEFAULT_LANDING_PAGE_HTML})
Returns:
gophish.models.Page -- The created landing page
"""
landing_page = Page(name='Example Landing Page', html=html)
try:
landing_page = api.pages.post(landing_page)
except Exception as e:
print('Unable to create landing page: {}'.format(e))
return landing_page
def generate_results(api,
campaign,
percent_opened=50,
percent_clicked=20,
percent_submitted=5,
percent_reported=20):
"""Generates campaign events
Arguments:
api {gophish.API} -- The authenticated Gophish API client
campaign {gophish.models.Campaign} -- The created campaign
Keyword Arguments:
percent_opened {int} -- The percent of emails to open (default: {50})
percent_clicked {int} -- The percent of links to click (default: {20})
percent_submitted {int} -- The percent of form submissions (default: {5})
percent_reported {int} -- The percent of emails to report (default: {20})
"""
for result in campaign.results:
# Create a "device" for this user
user_agent = faker.user_agent()
# Handle the email open events
should_open = random.randint(0, 100)
if should_open <= percent_opened:
open_email(campaign, result, user_agent=user_agent)
# Handle the link clicked events
should_click = random.randint(0, 100)
if should_click <= percent_clicked:
click_link(campaign, result, user_agent=user_agent)
# Handle the submissions events
should_submit = random.randint(0, 100)
if should_submit <= percent_submitted:
submit_data(campaign, result, user_agent=user_agent)
# Handle the reported events
should_report = random.randint(0, 100)
if should_report <= percent_reported:
report_email(campaign, result, user_agent=user_agent)
def open_email(campaign, result, user_agent=DEFAULT_USER_AGENT):
"""Generates an email opened event
Arguments:
campaign {gophish.models.Campaign} -- The campaign to generate the
event for
result {gophish.models.Result} -- The result to generate the event for
Keyword Arguments:
user_agent {str} -- The user agent used to generate the event
(default: {DEFAULT_USER_AGENT})
Returns:
requests.Response -- The response object for the HTTP request used to
create the event
"""
print('Opening email for {}'.format(result.email))
sys.stdout.flush()
return requests.get(
'{}/track'.format(campaign.url),
params={'rid': result.id},
headers={'User-Agent': user_agent})
def click_link(campaign, result, user_agent=DEFAULT_USER_AGENT):
"""Generates a clicked link event
Arguments:
campaign {gophish.models.Campaign} -- The campaign to generate the
event for
result {gophish.models.Result} -- The result to generate the event for
Keyword Arguments:
user_agent {str} -- The user agent used to generate the event
(default: {DEFAULT_USER_AGENT})
Returns:
requests.Response -- The response object for the HTTP request used to
create the event
"""
print('Clicking link for {}'.format(result.email))
sys.stdout.flush()
return requests.get(
campaign.url,
params={'rid': result.id},
headers={'User-Agent': user_agent})
def submit_data(campaign, result, user_agent=DEFAULT_USER_AGENT):
"""Generates a data submission event
Arguments:
campaign {gophish.models.Campaign} -- The campaign to generate the
event for
result {gophish.models.Result} -- The result to generate the event for
Keyword Arguments:
user_agent {str} -- The user agent used to generate the event
(default: {DEFAULT_USER_AGENT})
Returns:
requests.Response -- The response object for the HTTP request used to
create the event
"""
print('Submitting data for {}'.format(result.email))
sys.stdout.flush()
return requests.post(
campaign.url,
params={'rid': result.id},
data={
'email': result.email,
'password': faker.password()
},
headers={'User-Agent': user_agent})
def report_email(campaign, result, user_agent=DEFAULT_USER_AGENT):
"""Generates an email report event
Arguments:
campaign {gophish.models.Campaign} -- The campaign to generate the
event for
result {gophish.models.Result} -- The result to generate the event for
Keyword Arguments:
user_agent {str} -- The user agent used to generate the event
(default: {DEFAULT_USER_AGENT})
Returns:
requests.Response -- The response object for the HTTP request used to
create the event
"""
print('Reporting email for {}'.format(result.email))
sys.stdout.flush()
return requests.get(
'{}/report'.format(campaign.url),
params={'rid': result.id},
headers={'User-Agent': user_agent})
def main():
parser = argparse.ArgumentParser(
description='Loads demo data into a Gophish instance',
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument(
'--api-key', type=str, required=True, help='The Gophish API key')
parser.add_argument(
'--api-url',
type=str,
default='https://localhost:3333',
help='The URL pointing to the Gophish admin server')
parser.add_argument(
'--phish-url',
type=str,
default='http://localhost',
help='The URL pointing to the Gophish phishing server')
parser.add_argument(
'--num-groups',
type=int,
default=10,
help='The number of groups to create')
parser.add_argument(
'--num-members',
type=int,
default=100,
help='The number of recipients in each group')
parser.add_argument(
'--percent-opened',
type=int,
default=50,
help='Percent of users to open the emails in the campaign')
parser.add_argument(
'--percent-clicked',
type=int,
default=20,
help='Percent of users to click the links in the campaign')
parser.add_argument(
'--percent-submitted',
type=int,
default=5,
help='Percent of users to submit data in the campaign')
parser.add_argument(
'--percent-reported',
type=int,
default=5,
help='Percent of users to report the emails in the campaign')
args = parser.parse_args()
# Start our null SMTP server
smtp = Controller(Sink(), hostname='127.0.0.1')
smtp.start()
api = Gophish(api_key=args.api_key, host=args.api_url, verify=False)
# Generate our groups
print('Generating Groups...')
sys.stdout.flush()
group_names = generate_groups(
api, num_groups=args.num_groups, num_members=args.num_members)
groups = [Group(name=group) for group in group_names]
print('Generating SMTP')
sys.stdout.flush()
smtp = generate_sending_profile(api, '{}:{}'.format(
smtp.hostname, smtp.port))
print('Generating Template')
sys.stdout.flush()
template = generate_template(api)
print('Generating Landing Page')
sys.stdout.flush()
landing_page = generate_landing_page(api)
print('Generating Campaigns')
sys.stdout.flush()
campaign = Campaign(
name='Demo Campaign',
groups=groups,
page=landing_page,
template=template,
smtp=smtp,
url=args.phish_url)
campaign = api.campaigns.post(campaign)
# Wait for the emails to be received
while True:
summary = api.campaigns.summary(campaign_id=campaign.id)
if summary.stats.sent < len(campaign.results):
if summary.stats.error:
print(
'Encountered an error... Check the Gophish logs for details.'
)
print('Exiting...')
sys.exit(1)
print(
'Waiting for mock emails to finish sending (this takes a few seconds)...'
)
sys.stdout.flush()
time.sleep(1)
continue
break
generate_results(
api,
campaign,
percent_opened=args.percent_opened,
percent_clicked=args.percent_clicked,
percent_submitted=args.percent_submitted,
percent_reported=args.percent_reported)
print(
'\n\nAll set! You can now browse to {} to view the Gophish dashboard'.
format(args.api_url))
print('The credentials are admin:gophish')
print('Enjoy!')
if __name__ == '__main__':
main()