Closed DreadsCasey closed 3 months ago
Thanks for the report. We'll have to check if Impacket supports SMB/Samba to non-Windows, but I don't think it does... so I agree with your expectation that these errors should be handled with better output shown.
Impacket definitely supports non windows SMB servers, not sure why this one breaks though. Can you provide the SMB version the server uses?
Okay after taking a second look it looks to me like you have found valid credentials against that SMB server and nxc now tries to evaluate if you have admin privileges with MSRPC stuff which therefore fails because it isn't a windows host. So the best fix would probably be to not run the windows admin check if we can detect, that it is a linux host. If i recall correctly impacket should report whether it has found a windows host or linux host, so it's just down to a proper check.
That would be great to have the OS check, no clue how comprehensive it can be but being able to see Windows/Unix hosts in the output is handy. Currently I think it reports Windows 6.1 or something when the host is Unix running Samba.
So i took a deep dive into how to detect Unix systems. For SMBv1 that's super easy, it will just provide the NativeOS and lanmanager (Samba/Windows) as plaintext in the SMB data block. For SMBv3 i could not find anything in the MS-SMB2 documentation that would be suitable. Although, i found other aspects that can be used for finger printing:
I will add a check that will display "Unix" if we match these criteria and than also prevents the admin check.
Hi again, managed to create this error again with the latest build (just re-installed today). Works fine without any domain -d flag supplied, however once I do supplied a domain for use with authentication, the proto_flow() exception happens, except on different lines of connection.py.
Commands are exactly the same as before, without domain is works fine but doesn't report the host as Unix, this may also be due to invalid creds;
:~$ netexec smb 172.16.10.241 -u <user> -p '<pass>'
SMB 172.16.10.241 445 QUMULO [*] Windows 6.1 Build 7600 (name:QUMULO) (domain:QUMULO) (signing:False) (SMBv1:False)
SMB 172.16.10.241 445 QUMULO [-] <REDACTED> STATUS_LOGON_FAILURE
This could be specific to this host, as other Unix hosts the login and OS reporting works correctly
:~$ netexec smb 172.16.10.7-u <user> -p '<pass>' -d <domain>
SMB 172.16.10.7 445 UK-NAS02 [*] Unix - Samba (name:UK-NAS02) (domain:UK-NAS02) (signing:False) (SMBv1:False)
SMB 172.16.10.7 445 UK-NAS02 [+] <REDACTED>
Perhaps this is something to do with QUMULO and some proprietary Samba service going on, I really don't know enough to say for sure but thought I would post as it does still create allot of messy output that IMO, should be reserved for verbose or debug flag, especially in this case where I'm scanning a /24 and this clusters the output. Particularity as a lot of users of this tool may run into proprietary and undocumented technology built of standard tech (like being build off the Samba/SMB RFC) that may break functions.
:~$ netexec smb 172.16.10.241 -u <user> -p '<pass>' -d <domain>
SMB 172.16.10.241 445 QUMULO [*] Windows 6.1 Build 7600 (name:QUMULO) (domain:QUMULO) (signing:False) (SMBv1:False)
[10:08:17] ERROR Exception while calling proto_flow() on target 172.16.10.241: ('unpack requires a buffer of 1 bytes', "When unpacking field 'ver_major | B=5 | b''[:1]'") connection.py:168
╭──────────────────────────────────────────────────────────────────── Traceback (most recent call last) ────────────────────────────────────────────────────────────────────╮
│ /home/adam/.local/pipx/venvs/netexec/lib/python3.10/site-packages/nxc/connection.py:163 in __init__ │
│ │
│ 160 │ │ self.logger.info(f"Socket info: host={self.host}, hostname={self.hostname}, │
│ kerberos={self.kerberos}, ipv6={self.is_ipv6}, link-local │
│ ipv6={self.is_link_local_ipv6}") │
│ 161 │ │ │
│ 162 │ │ try: │
│ ❱ 163 │ │ │ self.proto_flow() │
│ 164 │ │ except Exception as e: │
│ 165 │ │ │ if "ERROR_DEPENDENT_SERVICES_RUNNING" in str(e): │
│ 166 │ │ │ │ self.logger.error(f"Exception while calling proto_flow() on target │
│ {target}: {e}") │
│ │
│ /home/adam/.local/pipx/venvs/netexec/lib/python3.10/site-packages/nxc/connection.py:223 in proto_flow │
│ │
│ 220 │ │ else: │
│ 221 │ │ │ self.logger.debug("Created connection object") │
│ 222 │ │ │ self.enum_host_info() │
│ ❱ 223 │ │ │ if self.print_host_info() and (self.login() or (self.username == "" and │
│ self.password == "")): │
│ 224 │ │ │ │ if hasattr(self.args, "module") and self.args.module: │
│ 225 │ │ │ │ │ self.load_modules() │
│ 226 │ │ │ │ │ self.logger.debug("Calling modules") │
│ │
│ /home/adam/.local/pipx/venvs/netexec/lib/python3.10/site-packages/nxc/connection.py:552 in login │
│ │
│ 549 │ │ if not self.args.no_bruteforce: │
│ 550 │ │ │ for secr_index, secr in enumerate(secret): │
│ 551 │ │ │ │ for user_index, user in enumerate(username): │
│ ❱ 552 │ │ │ │ │ if self.try_credentials(domain[user_index], user, owned[user_index], │
│ secr, cred_type[secr_index], data[secr_index]): │
│ 553 │ │ │ │ │ │ owned[user_index] = True │
│ 554 │ │ │ │ │ │ if not self.args.continue_on_success: │
│ 555 │ │ │ │ │ │ │ return True │
│ │
│ /home/adam/.local/pipx/venvs/netexec/lib/python3.10/site-packages/nxc/connection.py:487 in try_credentials │
│ │
│ 484 │ │ │ │ │ return self.kerberos_login(domain, username, secret, "", "", │
│ self.kdcHost, False) │
│ 485 │ │ │ │ elif hasattr(self.args, "domain"): # Some protocols don't use domain │
│ for login │
│ 486 │ │ │ │ │ self.logger.debug("Trying to authenticate using plaintext with │
│ domain") │
│ ❱ 487 │ │ │ │ │ return self.plaintext_login(domain, username, secret) │
│ 488 │ │ │ │ elif self.args.protocol == "ssh": │
│ 489 │ │ │ │ │ self.logger.debug("Trying to authenticate using plaintext over SSH") │
│ 490 │ │ │ │ │ return self.plaintext_login(username, secret, data) │
│ │
│ /home/adam/.local/pipx/venvs/netexec/lib/python3.10/site-packages/nxc/protocols/smb.py:399 in plaintext_login │
│ │
│ 396 │ │ │ self.is_guest = bool(self.conn.isGuestSession()) │
│ 397 │ │ │ self.logger.debug(f"{self.is_guest=}") │
│ 398 │ │ │ if "Unix" not in self.server_os: │
│ ❱ 399 │ │ │ │ self.check_if_admin() │
│ 400 │ │ │ self.logger.debug(f"Adding credential: │
│ {domain}/{self.username}:{self.password}") │
│ 401 │ │ │ self.db.add_credential("plaintext", domain, self.username, self.password) │
│ 402 │ │ │ user_id = self.db.get_credential("plaintext", domain, self.username, │
│ self.password) │
│ │
│ /home/adam/.local/pipx/venvs/netexec/lib/python3.10/site-packages/nxc/protocols/smb.py:570 in check_if_admin │
│ │
│ 567 │ │ │ try: │
│ 568 │ │ │ │ # 0xF003F - SC_MANAGER_ALL_ACCESS │
│ 569 │ │ │ │ # │
│ http://msdn.microsoft.com/en-us/library/windows/desktop/ms685981(v=vs.85).aspx │
│ ❱ 570 │ │ │ │ scmr.hROpenSCManagerW(dce, f"{self.host}\x00", "ServicesActive\x00", │
│ 0xF003F) │
│ 571 │ │ │ │ self.logger.debug(f"User is admin on {self.host}!") │
│ 572 │ │ │ │ self.admin_privs = True │
│ 573 │ │ │ except scmr.DCERPCException: │
│ │
│ /home/adam/.local/pipx/venvs/netexec/lib/python3.10/site-packages/impacket/dcerpc/v5/scmr.py:1338 in hROpenSCManagerW │
│ │
│ 1335 │ openSCManager['lpMachineName'] = checkNullString(lpMachineName) │
│ 1336 │ openSCManager['lpDatabaseName'] = checkNullString(lpDatabaseName) │
│ 1337 │ openSCManager['dwDesiredAccess'] = dwDesiredAccess │
│ ❱ 1338 │ return dce.request(openSCManager) │
│ 1339 │
│ 1340 def hROpenServiceW(dce, hSCManager, lpServiceName, dwDesiredAccess= SERVICE_ALL_ACCESS): │
│ 1341 │ openService = ROpenServiceW() │
│ │
│ /home/adam/.local/pipx/venvs/netexec/lib/python3.10/site-packages/impacket/dcerpc/v5/rpcrt.py:859 in request │
│ │
│ 856 │ │ │ isNDR64 = False │
│ 857 │ │ │
│ 858 │ │ self.call(request.opnum, request, uuid) │
│ ❱ 859 │ │ answer = self.recv() │
│ 860 │ │ │
│ 861 │ │ __import__(request.__module__) │
│ 862 │ │ module = sys.modules[request.__module__] │
│ │
│ /home/adam/.local/pipx/venvs/netexec/lib/python3.10/site-packages/impacket/dcerpc/v5/rpcrt.py:1311 in recv │
│ │
│ 1308 │ │ │ # At least give me the MSRPCRespHeader, especially important for │
│ 1309 │ │ │ # TCP/UDP Transports │
│ 1310 │ │ │ response_data = self._transport.recv(forceRecv, count=MSRPCRespHeader._SIZE) │
│ ❱ 1311 │ │ │ response_header = MSRPCRespHeader(response_data) │
│ 1312 │ │ │ # Ok, there might be situation, especially with large packets, that │
│ 1313 │ │ │ # the transport layer didn't send us the full packet's contents │
│ 1314 │ │ │ # So we gotta check we received it all │
│ │
│ /home/adam/.local/pipx/venvs/netexec/lib/python3.10/site-packages/impacket/dcerpc/v5/rpcrt.py:690 in __init__ │
│ │
│ 687 │ ) │
│ 688 │ │
│ 689 │ def __init__(self, aBuffer = None, alignment = 0): │
│ ❱ 690 │ │ MSRPCHeader.__init__(self, aBuffer, alignment) │
│ 691 │ │ if aBuffer is None: │
│ 692 │ │ │ self['type'] = MSRPC_RESPONSE │
│ 693 │ │ │ self['ctx_id'] = 0 │
│ │
│ /home/adam/.local/pipx/venvs/netexec/lib/python3.10/site-packages/impacket/dcerpc/v5/rpcrt.py:637 in __init__ │
│ │
│ 634 │ ) │
│ 635 │ │
│ 636 │ def __init__(self, data = None, alignment = 0): │
│ ❱ 637 │ │ Structure.__init__(self,data, alignment) │
│ 638 │ │ if data is None: │
│ 639 │ │ │ self['ver_major'] = 5 │
│ 640 │ │ │ self['ver_minor'] = 0 │
│ │
│ /home/adam/.local/pipx/venvs/netexec/lib/python3.10/site-packages/impacket/structure.py:89 in __init__ │
│ │
│ 86 │ │ self.fields = {} │
│ 87 │ │ self.rawData = data │
│ 88 │ │ if data is not None: │
│ ❱ 89 │ │ │ self.fromString(data) │
│ 90 │ │ else: │
│ 91 │ │ │ self.data = None │
│ 92 │
│ │
│ /home/adam/.local/pipx/venvs/netexec/lib/python3.10/site-packages/impacket/structure.py:154 in fromString │
│ │
│ 151 │ │ │ if len(field) > 2: │
│ 152 │ │ │ │ dataClassOrCode = field[2] │
│ 153 │ │ │ try: │
│ ❱ 154 │ │ │ │ self[field[0]] = self.unpack(field[1], data[:size], dataClassOrCode = │
│ dataClassOrCode, field = field[0]) │
│ 155 │ │ │ except Exception as e: │
│ 156 │ │ │ │ e.args += ("When unpacking field '%s | %s | %r[:%d]'" % (field[0], │
│ field[1], data, size),) │
│ 157 │ │ │ │ raise │
│ │
│ /home/adam/.local/pipx/venvs/netexec/lib/python3.10/site-packages/impacket/structure.py:328 in unpack │
│ │
│ 325 │ │ # code specifier │
│ 326 │ │ two = format.split('=') │
│ 327 │ │ if len(two) >= 2: │
│ ❱ 328 │ │ │ return self.unpack(two[0],data) │
│ 329 │ │ │
│ 330 │ │ # length specifier │
│ 331 │ │ two = format.split('-') │
│ │
│ /home/adam/.local/pipx/venvs/netexec/lib/python3.10/site-packages/impacket/structure.py:387 in unpack │
│ │
│ 384 │ │ │ return dataClassOrCode(data) │
│ 385 │ │ │
│ 386 │ │ # struct like specifier │
│ ❱ 387 │ │ return unpack(format, data)[0] │
│ 388 │ │
│ 389 │ def calcPackSize(self, format, data, field = None): │
│ 390 # # print " calcPackSize %s:%r" % (format, data) │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
error: ('unpack requires a buffer of 1 bytes', "When unpacking field 'ver_major | B=5 | b''[:1]'")
Ah yes this is because this service reports the build number 7600. @mpgn showed me another system reporting that build number. If anyone of you can manage to get root on the system so we could figure out which service hosts the smb server that would be really helpful. Maybe we can identify another smb service which we can detect.
Besides that I will add exception handling for that use case
Unfortunatly the test ended before we could get anymore info from that server, so it will remain a mystery. Exception handling would very useful however.
Well, atleast the stack trace should be fixed now :)
Closing for now, as this should be handled with #356
Describe the bug This bug seems to occur either due to login failing, or more likely because the host is not running Windows, and SMB connection was with a Samba host. The target was runnig Ubuntu This was noticed when scanning a network with credentials to determine which hosts the creds worked on. Output was unusable due to the errors taking up all the terminal output.
To Reproduce Username/password/domain have been redacted Command:
netexec smb 172.16.10.241 -u username -p password -d domain
Resulted in:Expected behavior At the least this level of output should be reserved for a verbose or debug flag, this would ensure the output would remain clean and allow the use to optionall view this information to debug issues with certain hosts.
However it would be nice to have some level of detection done to determine if it is a Unix host running Samba or a Winodws host.
NetExec info