From 1b7dbe3ba1867d9d7c6db88a8346601b4f0595e9 Mon Sep 17 00:00:00 2001 From: XiaoliChan <30458572+XiaoliChan@users.noreply.github.com> Date: Fri, 27 Dec 2024 01:26:55 +0800 Subject: [PATCH 1/4] [SMB] Allow force to use smbv2 Signed-off-by: XiaoliChan <30458572+XiaoliChan@users.noreply.github.com> --- nxc/protocols/smb.py | 15 +++++++++------ nxc/protocols/smb/proto_args.py | 1 + 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/nxc/protocols/smb.py b/nxc/protocols/smb.py index 676eaa762..01c039e99 100755 --- a/nxc/protocols/smb.py +++ b/nxc/protocols/smb.py @@ -583,22 +583,23 @@ def create_smbv3_conn(self): return False return True - def create_conn_obj(self, no_smbv1=False): + def create_conn_obj(self): """ Tries to create a connection object to the target host. On first try, it will try to create a SMBv1 connection. On further tries, it will remember which SMB version is supported and create a connection object accordingly. - - :param no_smbv1: If True, it will not try to create a SMBv1 connection """ + if self.args.force_smbv2: + return self.create_smbv3_conn() + # Initial negotiation - if not no_smbv1 and self.smbv1 is None: + if self.smbv1 is None: self.smbv1 = self.create_smbv1_conn() if self.smbv1: return True elif not self.is_timeouted: return self.create_smbv3_conn() - elif not no_smbv1 and self.smbv1: + elif self.smbv1: return self.create_smbv1_conn() else: return self.create_smbv3_conn() @@ -879,8 +880,10 @@ def shares(self): write = False write_dir = False write_file = False + pwd = ntpath.join("\\", "*") + pwd = ntpath.normpath(pwd) try: - self.conn.listPath(share_name, "*") + self.conn.listPath(share_name, pwd) read = True share_info["access"].append("READ") except SessionError as e: diff --git a/nxc/protocols/smb/proto_args.py b/nxc/protocols/smb/proto_args.py index 5f1875aa7..9f5ef4192 100644 --- a/nxc/protocols/smb/proto_args.py +++ b/nxc/protocols/smb/proto_args.py @@ -16,6 +16,7 @@ def proto_args(parser, parents): smb_parser.add_argument("--port", type=int, default=445, help="SMB port") smb_parser.add_argument("--share", metavar="SHARE", default="C$", help="specify a share") smb_parser.add_argument("--smb-server-port", default="445", help="specify a server port for SMB", type=int) + smb_parser.add_argument("--force-smbv2", action="store_true", help="Force to use SMBv2 in connection") smb_parser.add_argument("--gen-relay-list", metavar="OUTPUT_FILE", help="outputs all hosts that don't require SMB signing to the specified file") smb_parser.add_argument("--smb-timeout", help="SMB connection timeout", type=int, default=2) smb_parser.add_argument("--laps", dest="laps", metavar="LAPS", type=str, help="LAPS authentification", nargs="?", const="administrator") From d33f1640b7496e802204821d1dff6d15cb9b114a Mon Sep 17 00:00:00 2001 From: XiaoliChan <30458572+XiaoliChan@users.noreply.github.com> Date: Sat, 28 Dec 2024 02:10:50 +0800 Subject: [PATCH 2/4] [SMB] better control of smbv1 Signed-off-by: XiaoliChan <30458572+XiaoliChan@users.noreply.github.com> --- nxc/protocols/smb.py | 24 ++++++++++++++---------- nxc/protocols/smb/proto_args.py | 2 +- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/nxc/protocols/smb.py b/nxc/protocols/smb.py index 01c039e99..b52c68aa4 100755 --- a/nxc/protocols/smb.py +++ b/nxc/protocols/smb.py @@ -549,7 +549,6 @@ def create_smbv1_conn(self): preferredDialect=SMB_DIALECT, timeout=self.args.smb_timeout, ) - self.smbv1 = True except OSError as e: if "Connection reset by peer" in str(e): self.logger.info(f"SMBv1 might be disabled on {self.host}") @@ -577,20 +576,20 @@ def create_smbv3_conn(self): self.port, timeout=self.args.smb_timeout, ) - self.smbv1 = False except (Exception, NetBIOSTimeout, OSError) as e: self.logger.info(f"Error creating SMBv3 connection to {self.host}: {e}") return False return True - def create_conn_obj(self): + def create_conn_obj(self, no_smbv1=False): """ Tries to create a connection object to the target host. On first try, it will try to create a SMBv1 connection. On further tries, it will remember which SMB version is supported and create a connection object accordingly. + + :param no_smbv1: If True, it will not try to create a SMBv1 connection """ - if self.args.force_smbv2: - return self.create_smbv3_conn() + no_smbv1 = self.args.no_smbv1 if self.args.no_smbv1 else no_smbv1 # Initial negotiation if self.smbv1 is None: @@ -599,7 +598,7 @@ def create_conn_obj(self): return True elif not self.is_timeouted: return self.create_smbv3_conn() - elif self.smbv1: + elif not no_smbv1 and self.smbv1: return self.create_smbv1_conn() else: return self.create_smbv3_conn() @@ -841,6 +840,7 @@ def shares(self): temp_dir = ntpath.normpath("\\" + gen_random_string()) temp_file = ntpath.normpath("\\" + gen_random_string() + ".txt") permissions = [] + write_check = True if not self.args.no_write_check else False try: self.logger.debug(f"domain: {self.domain}") @@ -880,17 +880,21 @@ def shares(self): write = False write_dir = False write_file = False - pwd = ntpath.join("\\", "*") - pwd = ntpath.normpath(pwd) try: - self.conn.listPath(share_name, pwd) + self.conn.listPath(share_name, "*") read = True share_info["access"].append("READ") except SessionError as e: error = get_error_string(e) self.logger.debug(f"Error checking READ access on share {share_name}: {error}") + except (NetBIOSError, UnicodeEncodeError) as e: + write_check = False + share_info["access"].append("UNKNOWN (try '--no-smbv1')") + error = get_error_string(e) + self.logger.debug(f"Error checking READ access on share {share_name}: {error}. This exception always caused by special character in share name with SMBv1") + self.logger.info(f"Skipping WRITE permission check on share {share_name}") - if not self.args.no_write_check: + if write_check: try: self.conn.createDirectory(share_name, temp_dir) write_dir = True diff --git a/nxc/protocols/smb/proto_args.py b/nxc/protocols/smb/proto_args.py index 9f5ef4192..52078a30f 100644 --- a/nxc/protocols/smb/proto_args.py +++ b/nxc/protocols/smb/proto_args.py @@ -16,7 +16,7 @@ def proto_args(parser, parents): smb_parser.add_argument("--port", type=int, default=445, help="SMB port") smb_parser.add_argument("--share", metavar="SHARE", default="C$", help="specify a share") smb_parser.add_argument("--smb-server-port", default="445", help="specify a server port for SMB", type=int) - smb_parser.add_argument("--force-smbv2", action="store_true", help="Force to use SMBv2 in connection") + smb_parser.add_argument("--no-smbv1", action="store_true", help="Force to disable SMBv1 in connection") smb_parser.add_argument("--gen-relay-list", metavar="OUTPUT_FILE", help="outputs all hosts that don't require SMB signing to the specified file") smb_parser.add_argument("--smb-timeout", help="SMB connection timeout", type=int, default=2) smb_parser.add_argument("--laps", dest="laps", metavar="LAPS", type=str, help="LAPS authentification", nargs="?", const="administrator") From b79ddec91f9f712841049c1c7453322d2c1682c3 Mon Sep 17 00:00:00 2001 From: XiaoliChan <30458572+XiaoliChan@users.noreply.github.com> Date: Sun, 29 Dec 2024 01:43:12 +0800 Subject: [PATCH 3/4] [SMB] add e2e for '--no-smbv1' Signed-off-by: XiaoliChan <30458572+XiaoliChan@users.noreply.github.com> --- tests/e2e_commands.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/e2e_commands.txt b/tests/e2e_commands.txt index aadf55c79..491069288 100644 --- a/tests/e2e_commands.txt +++ b/tests/e2e_commands.txt @@ -5,6 +5,7 @@ netexec smb TARGET_HOST --generate-hosts-file /tmp/hostsfile netexec smb TARGET_HOST -u LOGIN_USERNAME -p LOGIN_PASSWORD KERBEROS # need an extra space after this command due to regex netexec {DNS} smb TARGET_HOST -u LOGIN_USERNAME -p LOGIN_PASSWORD KERBEROS netexec smb TARGET_HOST -u LOGIN_USERNAME -p LOGIN_PASSWORD KERBEROS --shares +netexec smb TARGET_HOST -u LOGIN_USERNAME -p LOGIN_PASSWORD KERBEROS --shares --no-smbv1 netexec smb TARGET_HOST -u LOGIN_USERNAME -p LOGIN_PASSWORD KERBEROS --shares --filter-shares READ WRITE netexec smb TARGET_HOST -u LOGIN_USERNAME -p LOGIN_PASSWORD KERBEROS --pass-pol netexec smb TARGET_HOST -u LOGIN_USERNAME -p LOGIN_PASSWORD KERBEROS --disks From 281feb3809f07ffb5f8cec810e83cc06f92cbf87 Mon Sep 17 00:00:00 2001 From: XiaoliChan <30458572+XiaoliChan@users.noreply.github.com> Date: Sun, 29 Dec 2024 18:29:05 +0800 Subject: [PATCH 4/4] [SMB] @mpgn review Signed-off-by: XiaoliChan <30458572+XiaoliChan@users.noreply.github.com> --- nxc/protocols/smb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nxc/protocols/smb.py b/nxc/protocols/smb.py index b52c68aa4..e9cd70f26 100755 --- a/nxc/protocols/smb.py +++ b/nxc/protocols/smb.py @@ -592,7 +592,7 @@ def create_conn_obj(self, no_smbv1=False): no_smbv1 = self.args.no_smbv1 if self.args.no_smbv1 else no_smbv1 # Initial negotiation - if self.smbv1 is None: + if not no_smbv1 and self.smbv1 is None: self.smbv1 = self.create_smbv1_conn() if self.smbv1: return True