Skip to content

Commit 8c4204b

Browse files
committed
Added --filter-pipe-name to filter on SMB named pipes names, fixes #46
Release 2.4
1 parent 8ec824e commit 8c4204b

File tree

16 files changed

+1336
-740
lines changed

16 files changed

+1336
-740
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
+ [x] Random UNC paths generation to avoid caching failed attempts (all modes)
2020
+ [x] Configurable delay between attempts with `--delay`
2121
- Options:
22-
+ [x] Filter by method name with `--filter-method-name` or by protocol name with `--filter-protocol-name` (all modes)
22+
+ [x] Filter by method name with `--filter-method-name`, by protocol name with `--filter-protocol-name` or by pipe name with `--filter-pipe-name`(all modes)
2323
+ [x] Target a single machine `--target` or a list of targets from a file with `--targets-file`
2424
+ [x] Specify IP address OR interface to listen on for incoming authentications. (modes [scan](./documentation/Scan-mode.md) and [fuzz](./documentation/Fuzz-mode.md))
2525
- Exporting results

coercer/__main__.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from coercer.network.smb import try_login
1919

2020

21-
VERSION = "2.3-blackhat-edition"
21+
VERSION = "2.4-blackhat-edition"
2222

2323
banner = """ ______
2424
/ ____/___ ___ _____________ _____
@@ -48,9 +48,10 @@ def parseArgs():
4848
mode_scan_advanced_config.add_argument("--smb-port", default=445, type=int, help="SMB port (default: 445)")
4949
mode_scan_advanced_config.add_argument("--auth-type", default=None, type=str, help="Desired authentication type ('smb' or 'http').")
5050
# Filters
51-
mode_scan_filters = mode_scan.add_argument_group("Filtering methods")
51+
mode_scan_filters = mode_scan.add_argument_group("Filtering")
5252
mode_scan_filters.add_argument("--filter-method-name", default=None, type=str, help="")
5353
mode_scan_filters.add_argument("--filter-protocol-name", default=None, type=str, help="")
54+
mode_scan_filters.add_argument("--filter-pipe-name", default=None, type=str, help="")
5455
# Credentials
5556
mode_scan_credentials = mode_scan.add_argument_group("Credentials")
5657
mode_scan_credentials.add_argument("-u", "--username", default="", help="Username to authenticate to the remote machine.")
@@ -82,9 +83,10 @@ def parseArgs():
8283
mode_fuzz_advanced_config.add_argument("--smb-port", default=445, type=int, help="SMB port (default: 445)")
8384
mode_fuzz_advanced_config.add_argument("--auth-type", default=None, type=str, help="Desired authentication type ('smb' or 'http').")
8485
# Filters
85-
mode_fuzz_filters = mode_fuzz.add_argument_group("Filtering methods")
86+
mode_fuzz_filters = mode_fuzz.add_argument_group("Filtering")
8687
mode_fuzz_filters.add_argument("--filter-method-name", default=None, type=str, help="")
8788
mode_fuzz_filters.add_argument("--filter-protocol-name", default=None, type=str, help="")
89+
mode_fuzz_filters.add_argument("--filter-pipe-name", default=None, type=str, help="")
8890
# Credentials
8991
mode_fuzz_credentials = mode_fuzz.add_argument_group("Credentials")
9092
mode_fuzz_credentials.add_argument("--only-known-exploit-paths", action="store_true", default=False, help="Only test known exploit paths for each functions")
@@ -114,9 +116,10 @@ def parseArgs():
114116
mode_coerce_advanced_config.add_argument("--always-continue", default=False, action="store_true", help="Always continue to coerce")
115117
mode_coerce_advanced_config.add_argument("--auth-type", default=None, type=str, help="Desired authentication type ('smb' or 'http').")
116118
# Filters
117-
mode_coerce_filters = mode_coerce.add_argument_group("Filtering methods")
119+
mode_coerce_filters = mode_coerce.add_argument_group("Filtering")
118120
mode_coerce_filters.add_argument("--filter-method-name", default=None, type=str, help="")
119121
mode_coerce_filters.add_argument("--filter-protocol-name", default=None, type=str, help="")
122+
mode_coerce_filters.add_argument("--filter-pipe-name", default=None, type=str, help="")
120123
# Credentials
121124
mode_coerce_credentials = mode_coerce.add_argument_group("Credentials")
122125
mode_coerce_credentials.add_argument("-u", "--username", default="", help="Username to authenticate to the machine.")
Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
11
#!/usr/bin/env python3
22
# -*- coding: utf-8 -*-
3-
# File name : MethodFilter.py
3+
# File name : Filter.py
44
# Author : Podalirius (@podalirius_)
55
# Date created : 15 Sep 2022
66

7-
class MethodFilter(object):
7+
class Filter(object):
88
"""
9-
Documentation for class MethodFilter
9+
Documentation for class Filter
1010
"""
1111

12-
def __init__(self, filter_method_name=None, filter_protocol_name=None):
13-
super(MethodFilter, self).__init__()
12+
def __init__(self, filter_method_name=None, filter_protocol_name=None, filter_pipe_name=None):
13+
super(Filter, self).__init__()
1414
self.filter_method_name = filter_method_name
1515
self.filter_protocol_name = filter_protocol_name
16+
self.filter_pipe_name = filter_pipe_name
1617

17-
def matches_filter(self, instance):
18+
def method_matches_filter(self, instance):
1819
"""
19-
Function matches_filter
20+
Function method_matches_filter
2021
2122
Parameters:
2223
?:instance
@@ -38,4 +39,22 @@ def matches_filter(self, instance):
3839
else:
3940
outcome = outcome and False
4041
return outcome
41-
42+
43+
def pipe_matches_filter(self, pipe_name):
44+
"""
45+
Function pipe_matches_filter
46+
47+
Parameters:
48+
?:pipe_name
49+
50+
Return:
51+
bool:outcome
52+
"""
53+
outcome = True
54+
#
55+
if self.filter_pipe_name is not None:
56+
if self.filter_pipe_name in pipe_name:
57+
outcome = outcome and True
58+
else:
59+
outcome = outcome and False
60+
return outcome

coercer/core/modes/coerce.py

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77

88
import time
9-
from coercer.core.MethodFilter import MethodFilter
9+
from coercer.core.Filter import Filter
1010
from coercer.core.utils import generate_exploit_path_from_template
1111
from coercer.network.DCERPCSession import DCERPCSession
1212
from coercer.structures.TestResult import TestResult
@@ -17,9 +17,10 @@
1717
def action_coerce(target, available_methods, options, credentials, reporter):
1818
reporter.verbose = True
1919

20-
method_filter = MethodFilter(
20+
filter = Filter(
2121
filter_method_name=options.filter_method_name,
22-
filter_protocol_name=options.filter_protocol_name
22+
filter_protocol_name=options.filter_protocol_name,
23+
filter_pipe_name=options.filter_pipe_name
2324
)
2425

2526
# Preparing tasks ==============================================================================================================
@@ -30,7 +31,7 @@ def action_coerce(target, available_methods, options, credentials, reporter):
3031
for method in sorted(available_methods[method_type][category].keys()):
3132
instance = available_methods[method_type][category][method]["class"]
3233

33-
if method_filter.matches_filter(instance):
34+
if filter.method_matches_filter(instance):
3435
for access_type, access_methods in instance.access.items():
3536
if access_type not in tasks.keys():
3637
tasks[access_type] = {}
@@ -39,17 +40,18 @@ def action_coerce(target, available_methods, options, credentials, reporter):
3940
if access_type == "ncan_np":
4041
for access_method in access_methods:
4142
namedpipe, uuid, version = access_method["namedpipe"], access_method["uuid"], access_method["version"]
42-
if namedpipe not in tasks[access_type].keys():
43-
tasks[access_type][namedpipe] = {}
43+
if filter.pipe_matches_filter(namedpipe):
44+
if namedpipe not in tasks[access_type].keys():
45+
tasks[access_type][namedpipe] = {}
4446

45-
if uuid not in tasks[access_type][namedpipe].keys():
46-
tasks[access_type][namedpipe][uuid] = {}
47+
if uuid not in tasks[access_type][namedpipe].keys():
48+
tasks[access_type][namedpipe][uuid] = {}
4749

48-
if version not in tasks[access_type][namedpipe][uuid].keys():
49-
tasks[access_type][namedpipe][uuid][version] = []
50+
if version not in tasks[access_type][namedpipe][uuid].keys():
51+
tasks[access_type][namedpipe][uuid][version] = []
5052

51-
if instance not in tasks[access_type][namedpipe][uuid][version]:
52-
tasks[access_type][namedpipe][uuid][version].append(instance)
53+
if instance not in tasks[access_type][namedpipe][uuid][version]:
54+
tasks[access_type][namedpipe][uuid][version].append(instance)
5355

5456
# Executing tasks =======================================================================================================================
5557

coercer/core/modes/fuzz.py

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77

88
import time
9-
from coercer.core.MethodFilter import MethodFilter
9+
from coercer.core.Filter import Filter
1010
from coercer.core.utils import generate_exploit_templates, generate_exploit_path_from_template
1111
from coercer.network.DCERPCSession import DCERPCSession
1212
from coercer.structures.TestResult import TestResult
@@ -16,9 +16,10 @@
1616

1717

1818
def action_fuzz(target, available_methods, options, credentials, reporter):
19-
method_filter = MethodFilter(
19+
filter = Filter(
2020
filter_method_name=options.filter_method_name,
21-
filter_protocol_name=options.filter_protocol_name
21+
filter_protocol_name=options.filter_protocol_name,
22+
filter_pipe_name=options.filter_pipe_name
2223
)
2324

2425
http_listen_port = 0
@@ -48,9 +49,25 @@ def action_fuzz(target, available_methods, options, credentials, reporter):
4849
r'\PIPE\W32TIME_ALT',
4950
r'\PIPE\wkssvc'
5051
]
51-
# \PIPE\Winsock2\CatalogChangeListener-71c-0
52+
if options.verbose:
53+
print("[debug] Using integrated list of %d SMB named pipes." % len(named_pipe_of_remote_machine))
5254
else:
5355
named_pipe_of_remote_machine = list_remote_pipes(target, credentials)
56+
if options.verbose:
57+
print("[debug] Found %d SMB named pipes on the remote machine." % len(named_pipe_of_remote_machine))
58+
59+
kept_pipes_after_filters = []
60+
for pipe in named_pipe_of_remote_machine:
61+
if filter.pipe_matches_filter(pipe):
62+
kept_pipes_after_filters.append(pipe)
63+
if len(kept_pipes_after_filters) == 0 and not credentials.is_anonymous():
64+
print("[!] No SMB named pipes matching filter --filter-pipe-name '%s' were found on the remote machine." % options.filter_pipe_name)
65+
return None
66+
elif len(kept_pipes_after_filters) == 0 and credentials.is_anonymous():
67+
print("[!] No SMB named pipes matching filter --filter-pipe-name '%s' were found in the list of known named pipes." % options.filter_pipe_name)
68+
return None
69+
else:
70+
named_pipe_of_remote_machine = kept_pipes_after_filters
5471

5572
# Preparing tasks ==============================================================================================================
5673

@@ -60,7 +77,7 @@ def action_fuzz(target, available_methods, options, credentials, reporter):
6077
for method in sorted(available_methods[method_type][category].keys()):
6178
instance = available_methods[method_type][category][method]["class"]
6279

63-
if method_filter.matches_filter(instance):
80+
if filter.method_matches_filter(instance):
6481
for access_type, access_methods in instance.access.items():
6582
if access_type not in tasks.keys():
6683
tasks[access_type] = {}
@@ -69,6 +86,7 @@ def action_fuzz(target, available_methods, options, credentials, reporter):
6986
if access_type == "ncan_np":
7087
for access_method in access_methods:
7188
namedpipe, uuid, version = access_method["namedpipe"], access_method["uuid"], access_method["version"]
89+
# if filter.pipe_matches_filter(namedpipe):
7290
if uuid not in tasks[access_type].keys():
7391
tasks[access_type][uuid] = {}
7492

@@ -108,6 +126,7 @@ def action_fuzz(target, available_methods, options, credentials, reporter):
108126
continue
109127
if listener_type == "http":
110128
http_listen_port = get_next_http_listener_port(current_value=http_listen_port, listen_ip=listening_ip, options=options)
129+
111130
exploitpath = generate_exploit_path_from_template(
112131
template=exploitpath,
113132
listener=listening_ip,

coercer/core/modes/scan.py

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77

88
import time
9-
from coercer.core.MethodFilter import MethodFilter
9+
from coercer.core.Filter import Filter
1010
from coercer.core.utils import generate_exploit_path_from_template
1111
from coercer.network.DCERPCSession import DCERPCSession
1212
from coercer.structures.TestResult import TestResult
@@ -18,9 +18,10 @@
1818
def action_scan(target, available_methods, options, credentials, reporter):
1919
http_listen_port = 0
2020

21-
method_filter = MethodFilter(
21+
filter = Filter(
2222
filter_method_name=options.filter_method_name,
23-
filter_protocol_name=options.filter_protocol_name
23+
filter_protocol_name=options.filter_protocol_name,
24+
filter_pipe_name=options.filter_pipe_name
2425
)
2526

2627
# Preparing tasks ==============================================================================================================
@@ -31,7 +32,7 @@ def action_scan(target, available_methods, options, credentials, reporter):
3132
for method in sorted(available_methods[method_type][category].keys()):
3233
instance = available_methods[method_type][category][method]["class"]
3334

34-
if method_filter.matches_filter(instance):
35+
if filter.method_matches_filter(instance):
3536
for access_type, access_methods in instance.access.items():
3637
if access_type not in tasks.keys():
3738
tasks[access_type] = {}
@@ -40,17 +41,18 @@ def action_scan(target, available_methods, options, credentials, reporter):
4041
if access_type == "ncan_np":
4142
for access_method in access_methods:
4243
namedpipe, uuid, version = access_method["namedpipe"], access_method["uuid"], access_method["version"]
43-
if namedpipe not in tasks[access_type].keys():
44-
tasks[access_type][namedpipe] = {}
44+
if filter.pipe_matches_filter(namedpipe):
45+
if namedpipe not in tasks[access_type].keys():
46+
tasks[access_type][namedpipe] = {}
4547

46-
if uuid not in tasks[access_type][namedpipe].keys():
47-
tasks[access_type][namedpipe][uuid] = {}
48+
if uuid not in tasks[access_type][namedpipe].keys():
49+
tasks[access_type][namedpipe][uuid] = {}
4850

49-
if version not in tasks[access_type][namedpipe][uuid].keys():
50-
tasks[access_type][namedpipe][uuid][version] = []
51+
if version not in tasks[access_type][namedpipe][uuid].keys():
52+
tasks[access_type][namedpipe][uuid][version] = []
5153

52-
if instance not in tasks[access_type][namedpipe][uuid][version]:
53-
tasks[access_type][namedpipe][uuid][version].append(instance)
54+
if instance not in tasks[access_type][namedpipe][uuid][version]:
55+
tasks[access_type][namedpipe][uuid][version].append(instance)
5456

5557
# Executing tasks =======================================================================================================================
5658

@@ -78,6 +80,7 @@ def action_scan(target, available_methods, options, credentials, reporter):
7880
continue
7981
if listener_type == "http":
8082
http_listen_port = get_next_http_listener_port(current_value=http_listen_port, listen_ip=listening_ip, options=options)
83+
8184
exploitpath = generate_exploit_path_from_template(
8285
template=exploitpath,
8386
listener=listening_ip,

coercer/network/Listener.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ def start_http(self, control_structure, http_port=80):
7575
s.listen(5)
7676
conn, address = s.accept()
7777
data = conn.recv(2048)
78-
print("\n",data,"\n")
78+
# print("\n",data,"\n")
7979
if b'HTTP' in data:
8080
control_structure["result"] = TestResult.HTTP_AUTH_RECEIVED
8181
except Exception as e:

documentation/coercer/core.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929

3030
<h2>Submodules</h2>
3131
<ul>
32-
<li><a href="core/MethodFilter.html">MethodFilter</a></li>
32+
<li><a href="core/Filter.html">Filter</a></li>
3333
<li><a href="core/Reporter.html">Reporter</a></li>
3434
<li><a href="core/loader.html">loader</a></li>
3535
<li><a href="core/modes.html">modes</a></li>

0 commit comments

Comments
 (0)