Skip to content

Commit 3956e06

Browse files
Merge branch 'p0dalirius:master' into ntlm-scan
2 parents 5effdba + 400880f commit 3956e06

File tree

9 files changed

+443
-56
lines changed

9 files changed

+443
-56
lines changed

LICENSE

+339
Large diffs are not rendered by default.

Makefile

+3-3
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ install: build
1717

1818
build:
1919
python3 -m pip uninstall coercer --yes --break-system-packages
20-
pip install .[build] --break-system-packages
20+
python3 -m pip install .[build] --break-system-packages
2121
python3 -m build --wheel
2222

2323
upload: build
24-
pip install .[twine] --break-system-packages
25-
twine upload dist/*
24+
python3 -m pip install .[twine] --break-system-packages
25+
python3 -m twine upload dist/*

coercer/__main__.py

+50-16
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
import argparse
99
import os
1010
import sys
11-
11+
from sectools.network.domains import is_fqdn
12+
from sectools.network.ip import is_ipv4_cidr, is_ipv4_addr, is_ipv6_addr, expand_cidr, expand_port_range
1213
from coercer.core.Reporter import Reporter
1314
from coercer.structures.Credentials import Credentials
1415
from coercer.core.modes.scan import action_scan
@@ -187,7 +188,38 @@ def main():
187188
print("[!] Could not open targets file '%s'." % options.targets_file)
188189
sys.exit(0)
189190

190-
credentials = Credentials(username=options.username, password=options.password, domain=options.domain, lmhash=lmhash, nthash=nthash)
191+
# Sort uniq on targets list
192+
targets = sorted(list(set(targets)))
193+
194+
final_targets = []
195+
# Parsing target to filter IP/DNS/CIDR
196+
for target in targets:
197+
if is_ipv4_cidr(target):
198+
final_targets += [ip for ip in expand_cidr(target)]
199+
elif is_ipv4_addr(target):
200+
final_targets.append(target)
201+
elif is_ipv6_addr(target):
202+
final_targets.append(target)
203+
elif is_fqdn(target):
204+
final_targets.append(target)
205+
elif target.startswith("http://") or target.startswith("https://"):
206+
import urllib.parse
207+
target = urllib.parse.urlparse(target).netloc
208+
final_targets.append(target)
209+
else:
210+
if options.debug:
211+
print("[debug] Target '%s' was not added." % target)
212+
213+
# Sort
214+
targets = sorted(list(set(final_targets)))
215+
216+
credentials = Credentials(
217+
username=options.username,
218+
password=options.password,
219+
domain=options.domain,
220+
lmhash=lmhash,
221+
nthash=nthash
222+
)
191223

192224
# Processing actions
193225
if options.mode == "coerce":
@@ -214,13 +246,14 @@ def main():
214246
if not "msrpc" in options.filter_transport_name or try_login(credentials, target, verbose=options.verbose):
215247
# Starting action
216248
action_scan(target, available_methods, options, credentials, reporter)
217-
# Reporting results
218-
if options.export_json is not None:
219-
reporter.exportJSON(options.export_json)
220-
if options.export_xlsx is not None:
221-
reporter.exportXLSX(options.export_xlsx)
222-
if options.export_sqlite is not None:
223-
reporter.exportSQLITE(target, options.export_sqlite)
249+
250+
# Reporting results
251+
if options.export_json is not None:
252+
reporter.exportJSON(options.export_json)
253+
if options.export_xlsx is not None:
254+
reporter.exportXLSX(options.export_xlsx)
255+
if options.export_sqlite is not None:
256+
reporter.exportSQLITE(options.export_sqlite)
224257

225258
elif options.mode == "fuzz":
226259
reporter.print_info("Starting fuzz mode")
@@ -235,13 +268,14 @@ def main():
235268
if not "msrpc" in options.filter_transport_name or try_login(credentials, target, verbose=options.verbose):
236269
# Starting action
237270
action_fuzz(target, available_methods, options, credentials, reporter)
238-
# Reporting results
239-
if options.export_json is not None:
240-
reporter.exportJSON(options.export_json)
241-
if options.export_xlsx is not None:
242-
reporter.exportXLSX(options.export_xlsx)
243-
if options.export_sqlite is not None:
244-
reporter.exportSQLITE(target, options.export_sqlite)
271+
272+
# Reporting results
273+
if options.export_json is not None:
274+
reporter.exportJSON(options.export_json)
275+
if options.export_xlsx is not None:
276+
reporter.exportXLSX(options.export_xlsx)
277+
if options.export_sqlite is not None:
278+
reporter.exportSQLITE(options.export_sqlite)
245279

246280
print("[+] All done! Bye Bye!")
247281

coercer/core/Reporter.py

+41-36
Original file line numberDiff line numberDiff line change
@@ -43,19 +43,21 @@ def print_warn(self, message):
4343
def print_verbose(self, message):
4444
print("[debug]",message)
4545

46-
def report_test_result(self, uuid, version, namedpipe, msprotocol_rpc_instance, result, exploitpath):
46+
def report_test_result(self, target, uuid, version, namedpipe, msprotocol_rpc_instance, result, exploitpath):
4747
function_name = msprotocol_rpc_instance.function["name"]
48-
if uuid not in self.test_results.keys():
49-
self.test_results[uuid] = {}
50-
if version not in self.test_results[uuid].keys():
51-
self.test_results[uuid][version] = {}
52-
if function_name not in self.test_results[uuid][version].keys():
53-
self.test_results[uuid][version][function_name] = {}
54-
if namedpipe not in self.test_results[uuid][version][function_name].keys():
55-
self.test_results[uuid][version][function_name][namedpipe] = []
48+
if target not in self.test_results.keys():
49+
self.test_results[target] = {}
50+
if uuid not in self.test_results[target].keys():
51+
self.test_results[target][uuid] = {}
52+
if version not in self.test_results[target][uuid].keys():
53+
self.test_results[target][uuid][version] = {}
54+
if function_name not in self.test_results[target][uuid][version].keys():
55+
self.test_results[target][uuid][version][function_name] = {}
56+
if namedpipe not in self.test_results[target][uuid][version][function_name].keys():
57+
self.test_results[target][uuid][version][function_name][namedpipe] = []
5658

5759
# Save result to database
58-
self.test_results[uuid][version][function_name][namedpipe].append({
60+
self.test_results[target][uuid][version][function_name][namedpipe].append({
5961
"function": msprotocol_rpc_instance.function,
6062
"protocol": msprotocol_rpc_instance.protocol,
6163
"testresult": result.name,
@@ -102,21 +104,22 @@ def exportXLSX(self, filename):
102104
worksheet = workbook.add_worksheet()
103105

104106
header_format = workbook.add_format({'bold': 1})
105-
header_fields = ["Interface UUID", "Interface version", "SMB named pipe", "Protocol long name", "Protocol short name", "RPC function name", "Operation number", "Result", "Working path"]
107+
header_fields = ["Target", "Interface UUID", "Interface version", "SMB named pipe", "Protocol long name", "Protocol short name", "RPC function name", "Operation number", "Result", "Working path"]
106108
for k in range(len(header_fields)):
107109
worksheet.set_column(k, k + 1, len(header_fields[k]) + 3)
108110
worksheet.set_row(0, 60, header_format)
109111
worksheet.write_row(0, 0, header_fields)
110112

111113
row_id = 1
112-
for uuid in self.test_results.keys():
113-
for version in self.test_results[uuid].keys():
114-
for function_name in self.test_results[uuid][version].keys():
115-
for namedpipe in self.test_results[uuid][version][function_name].keys():
116-
for test_result in self.test_results[uuid][version][function_name][namedpipe]:
117-
data = [uuid, version, namedpipe, test_result["protocol"]["longname"], test_result["protocol"]["shortname"], test_result["function"]["name"], test_result["function"]["opnum"], test_result["testresult"], test_result["exploitpath"]]
118-
worksheet.write_row(row_id, 0, data)
119-
row_id += 1
114+
for target in self.test_results.keys():
115+
for uuid in self.test_results[target].keys():
116+
for version in self.test_results[target][uuid].keys():
117+
for function_name in self.test_results[target][uuid][version].keys():
118+
for namedpipe in self.test_results[target][uuid][version][function_name].keys():
119+
for test_result in self.test_results[target][uuid][version][function_name][namedpipe]:
120+
data = [target, uuid, version, namedpipe, test_result["protocol"]["longname"], test_result["protocol"]["shortname"], test_result["function"]["name"], test_result["function"]["opnum"], test_result["testresult"], test_result["exploitpath"]]
121+
worksheet.write_row(row_id, 0, data)
122+
row_id += 1
120123
worksheet.autofilter(0, 0, row_id, len(header_fields) - 1)
121124
workbook.close()
122125
self.print_info("Results exported to XLSX in '%s'" % path_to_file)
@@ -136,7 +139,7 @@ def exportJSON(self, filename):
136139
f.close()
137140
self.print_info("Results exported to JSON in '%s'" % path_to_file)
138141

139-
def exportSQLITE(self, target, filename):
142+
def exportSQLITE(self, filename):
140143
basepath = os.path.dirname(filename)
141144
filename = os.path.basename(filename)
142145
if basepath not in [".", ""]:
@@ -151,23 +154,25 @@ def exportSQLITE(self, target, filename):
151154
# Creating a cursor object using the cursor() method
152155
cursor = conn.cursor()
153156
cursor.execute("CREATE TABLE IF NOT EXISTS results(target VARCHAR(255), uuid VARCHAR(255), version VARCHAR(255), named_pipe VARCHAR(255), protocol_shortname VARCHAR(255), protocol_longname VARCHAR(512), function_name VARCHAR(255), result VARCHAR(255), path VARCHAR(512));")
154-
for uuid in self.test_results.keys():
155-
for version in self.test_results[uuid].keys():
156-
for function_name in self.test_results[uuid][version].keys():
157-
for named_pipe in self.test_results[uuid][version][function_name].keys():
158-
for test_result in self.test_results[uuid][version][function_name][named_pipe]:
159-
cursor.execute("INSERT INTO results VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", (
160-
target,
161-
uuid,
162-
version,
163-
named_pipe,
164-
test_result["protocol"]["shortname"],
165-
test_result["protocol"]["longname"],
166-
function_name,
167-
test_result["testresult"],
168-
str(bytes(test_result["exploitpath"], 'utf-8'))[2:-1].replace('\\\\', '\\')
157+
cursor.execute("DELETE FROM results;")
158+
for target in self.test_results.keys():
159+
for uuid in self.test_results[target].keys():
160+
for version in self.test_results[target][uuid].keys():
161+
for function_name in self.test_results[target][uuid][version].keys():
162+
for named_pipe in self.test_results[target][uuid][version][function_name].keys():
163+
for test_result in self.test_results[target][uuid][version][function_name][named_pipe]:
164+
cursor.execute("INSERT INTO results VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", (
165+
target,
166+
uuid,
167+
version,
168+
named_pipe,
169+
test_result["protocol"]["shortname"],
170+
test_result["protocol"]["longname"],
171+
function_name,
172+
test_result["testresult"],
173+
str(bytes(test_result["exploitpath"], 'utf-8'))[2:-1].replace('\\\\', '\\')
174+
)
169175
)
170-
)
171176
# Commit your changes in the database
172177
conn.commit()
173178
# Closing the connection

coercer/core/modes/coerce.py

+2
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ def action_coerce(target, available_methods, options, credentials, reporter):
127127
)
128128

129129
reporter.report_test_result(
130+
target=target,
130131
uuid=uuid, version=version, namedpipe="",
131132
msprotocol_rpc_instance=msprotocol_rpc_instance,
132133
result=result,
@@ -201,6 +202,7 @@ def action_coerce(target, available_methods, options, credentials, reporter):
201202
)
202203

203204
reporter.report_test_result(
205+
target=target,
204206
uuid=uuid, version=version, namedpipe=namedpipe,
205207
msprotocol_rpc_instance=msprotocol_rpc_instance,
206208
result=result,

coercer/core/modes/fuzz.py

+2
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ def action_fuzz(target, available_methods, options, credentials, reporter):
177177
)
178178

179179
reporter.report_test_result(
180+
target=target,
180181
uuid=uuid, version=version, namedpipe=namedpipe,
181182
msprotocol_rpc_instance=msprotocol_rpc_instance,
182183
result=result,
@@ -247,6 +248,7 @@ def action_fuzz(target, available_methods, options, credentials, reporter):
247248
)
248249

249250
reporter.report_test_result(
251+
target=target,
250252
uuid=uuid, version=version, namedpipe=namedpipe,
251253
msprotocol_rpc_instance=msprotocol_rpc_instance,
252254
result=result,

coercer/core/modes/scan.py

+2
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ def action_scan(target, available_methods, options, credentials, reporter):
135135
)
136136

137137
reporter.report_test_result(
138+
target=target,
138139
uuid=uuid, version=version, namedpipe=namedpipe,
139140
msprotocol_rpc_instance=msprotocol_rpc_instance,
140141
result=result,
@@ -206,6 +207,7 @@ def action_scan(target, available_methods, options, credentials, reporter):
206207
)
207208

208209
reporter.report_test_result(
210+
target=target,
209211
uuid=uuid, version=version, namedpipe=namedpipe,
210212
msprotocol_rpc_instance=msprotocol_rpc_instance,
211213
result=result,

pyproject.toml

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ authors = ["p0dalirius"]
88
python = "^3.7"
99
impacket = "^0.10.0"
1010
xlsxWriter = ">=3.0.0"
11+
jinja2 = ">=3.1.3"
12+
sectools = ">=1.4.3"
1113

1214
[tool.poetry.dev-dependencies]
1315

requirements.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
impacket
22
xlsxwriter
3-
jinja2
3+
jinja2
4+
sectools

0 commit comments

Comments
 (0)