Skip to content

Commit e8efdf6

Browse files
committed
Allow fierce to be imported and called as a library
Fix output of subdomains section Previously, subdomains would be output completely differently to all other sections. This is resolved in this commit. Fix fierce usage for library Tested against main code base. Return to as close to master as possible
1 parent eacf1f2 commit e8efdf6

File tree

1 file changed

+71
-18
lines changed

1 file changed

+71
-18
lines changed

fierce/fierce.py

Lines changed: 71 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,30 @@ def fatal(msg, return_code=-1):
2727
exit(return_code)
2828

2929

30-
def print_subdomain_result(url, ip, http_connection_headers=None, nearby=None, stream=sys.stdout):
31-
print("Found: {} ({})".format(url, ip), file=stream)
30+
def print_subdomain_result(url, ip, http_connection_headers=None, nearby=None, stream=sys.stdout, printOutput=True):
31+
if not printOutput:
32+
output = {}
33+
output["subdomains"] = {}
34+
output["subdomains"]["http"] = ""
35+
output["subdomains"]["nearby"] = ""
36+
if printOutput:
37+
print("Found: {} ({})".format(url, ip), file=stream)
38+
else:
39+
output["subdomains"][url] = ip
3240

3341
if http_connection_headers:
34-
print("HTTP connected:", file=stream)
35-
pprint.pprint(http_connection_headers, stream=stream)
42+
if printOutput:
43+
print("HTTP connected:", file=stream)
44+
pprint.pprint(http_connection_headers, stream=stream)
45+
else:
46+
output["subdomains"]["http"]["url"] = http_connection_headers
3647

3748
if nearby:
38-
print("Nearby:", file=stream)
39-
pprint.pprint(nearby, stream=stream)
49+
if printOutput:
50+
print("Nearby:", file=stream)
51+
pprint.pprint(nearby, stream=stream)
52+
else:
53+
output["subdomains"]["nearby"] = nearby
4054

4155

4256
def unvisited_closure():
@@ -281,6 +295,10 @@ def update_resolver_nameservers(resolver, nameservers, nameserver_filename):
281295

282296

283297
def fierce(**kwargs):
298+
printOutput = kwargs.get("printOutput", True)
299+
if not printOutput:
300+
output = {}
301+
284302
resolver = dns.resolver.Resolver()
285303

286304
resolver = update_resolver_nameservers(
@@ -295,12 +313,17 @@ def fierce(**kwargs):
295313
resolver,
296314
range_ips,
297315
)
298-
if nearby:
316+
if nearby and printOutput:
299317
print("Nearby:")
300318
pprint.pprint(nearby)
319+
else:
320+
output["nearby"] = nearby
301321

302322
if not kwargs.get("domain"):
303-
return
323+
if not printOutput:
324+
return
325+
else:
326+
return output
304327

305328
domain = dns.name.from_text(kwargs['domain'])
306329
if not domain.is_absolute():
@@ -313,35 +336,59 @@ def fierce(**kwargs):
313336
else:
314337
domain_name_servers = []
315338

316-
print("NS: {}".format(" ".join(domain_name_servers) if ns else "failure"))
339+
if printOutput:
340+
print("NS: {}".format(" ".join(domain_name_servers) if ns else "failure"))
341+
else:
342+
output["NS"] = " ".join(domain_name_servers) if ns else "failure"
317343

318344
soa = recursive_query(resolver, domain, record_type='SOA', tcp=kwargs["tcp"])
319345
if soa:
320346
soa_mname = soa[0].mname
321347
master = query(resolver, soa_mname, record_type='A', tcp=kwargs["tcp"])
322348
master_address = master[0].address
323-
print("SOA: {} ({})".format(soa_mname, master_address))
349+
if printOutput:
350+
print("SOA: {} ({})".format(soa_mname, master_address))
351+
else:
352+
output["SOA"] = "{} ({})".format(soa_mname, master_address)
324353
else:
325-
print("SOA: failure")
326-
fatal("Failed to lookup NS/SOA, Domain does not exist")
354+
if printOutput:
355+
print("SOA: failure")
356+
fatal("Failed to lookup NS/SOA, Domain does not exist")
357+
else:
358+
output["SOA"] = "Failed to lookup NS/SOA, Domain does not exist"
359+
return output
327360

328361
zone = zone_transfer(master_address, domain)
329-
print("Zone: {}".format("success" if zone else "failure"))
362+
if printOutput:
363+
print("Zone: {}".format("success" if zone else "failure"))
364+
elif not zone:
365+
output["zone"] = "failure"
330366
if zone:
331-
pprint.pprint({k: v.to_text(k) for k, v in zone.items()})
332-
return
367+
if printOutput:
368+
pprint.pprint({k: v.to_text(k) for k, v in zone.items()})
369+
return
370+
else:
371+
output["zone"] = {}
372+
for k, v in zone.items():
373+
key = k.to_unicode()
374+
output["zone"][key] = {}
375+
output["zone"][key] = v.to_text(k).split('\n')
376+
return output
333377

334378
random_subdomain = str(random.randint(1e10, 1e11)) # noqa DUO102, non-cryptographic random use
335379
random_domain = concatenate_subdomains(domain, [random_subdomain])
336380
wildcard = query(resolver, random_domain, record_type='A', tcp=kwargs["tcp"])
337381
wildcard_ips = set(rr.address for rr in wildcard.rrset) if wildcard else set()
338-
print("Wildcard: {}".format(', '.join(wildcard_ips) if wildcard_ips else "failure"))
382+
wildcard = query(resolver, random_domain, record_type='A')
383+
if printOutput:
384+
print("Wildcard: {}".format(', '.join(wildcard_ips) if wildcard_ips else "failure"))
385+
else:
386+
output["Wildcard"] = wildcard_ips if wildcard else "failure"
339387

340388
subdomains = get_subdomains(
341389
kwargs["subdomains"],
342390
kwargs["subdomain_file"]
343391
)
344-
345392
filter_func = None
346393
if kwargs.get("search"):
347394
filter_func = functools.partial(search_filter, kwargs["search"])
@@ -353,7 +400,6 @@ def fierce(**kwargs):
353400
expander_func = functools.partial(traverse_expander, n=kwargs["traverse"])
354401

355402
unvisited = unvisited_closure()
356-
357403
for subdomain in subdomains:
358404
url = concatenate_subdomains(domain, [subdomain])
359405
record = query(resolver, url, record_type='A', tcp=kwargs["tcp"])
@@ -380,15 +426,22 @@ def fierce(**kwargs):
380426
filter_func=filter_func
381427
)
382428

429+
# TODO: Add this to lib
383430
print_subdomain_result(
384431
url,
385432
ip,
386433
http_connection_headers=http_connection_headers,
387434
nearby=nearby
388435
)
436+
if "subdomains" not in output.keys():
437+
output["subdomains"] = {}
438+
if not printOutput:
439+
output["subdomains"][url.to_text()] = record.response.answer[0].to_text()
389440

390441
if kwargs.get("delay"):
391442
time.sleep(kwargs["delay"])
443+
if not printOutput:
444+
return output
392445

393446

394447
def parse_args(args):

0 commit comments

Comments
 (0)