diff --git a/opencanary/modules/samba.py b/opencanary/modules/samba.py index 0c4967f..e57c27e 100644 --- a/opencanary/modules/samba.py +++ b/opencanary/modules/samba.py @@ -10,40 +10,61 @@ def __init__(self, logFile=None, logger=None): FileSystemWatcher.__init__(self, fileName=logFile) def handleLines(self, lines=None): - audit_re = re.compile(r"^.*smbd_audit.*: (.*$)") + # Updated regex to match anywhere in the line (not just at start). + # Samba 4.x may prepend a syslog timestamp before the smbd_audit token, + # causing the original anchored regex (^.*smbd_audit) to fail. + audit_re = re.compile(r"smbd_audit.*:\s*(.*$)") for line in lines: - matches = audit_re.match(line) + matches = audit_re.search(line) # Skip lines that do not match the correct RegEx pattern if matches is None: continue - data = matches.groups()[0].split("|") + raw_data = matches.groups()[0].split("|") - user = data[0] + # Samba 4.22+ with vfs_full_audit prefix "%U|%I|%S" produces + # 6 fields: user|srcHost|shareName|action|status|path + # Older Samba with extended prefix produces 13+ fields. + # Pad to 13 elements so existing field indices remain valid. + data = raw_data + [""] * max(0, 13 - len(raw_data)) + + user = data[0] if data[0] else "anonymous" srcHost = data[1] - dstHost = data[2] - srcHostName = data[3] - shareName = data[4] - dstHostName = data[5] - smbVersion = data[6] - smbArch = data[7] - domainName = data[9] - auditAction = data[10] - auditStatus = data[11] - path = data[12] - if user == "": - user = "anonymous" + if len(raw_data) <= 6: + # Short format (Samba 4.22+): user|srcHost|shareName|action|status|path + shareName = data[2] + auditAction = data[3] + auditStatus = data[4] + path = data[5] if len(raw_data) > 5 else "" + dstHost = "" + srcHostName = "" + dstHostName = "" + smbVersion = "" + smbArch = "" + domainName = "" + else: + # Long format (older Samba) + dstHost = data[2] + srcHostName = data[3] + shareName = data[4] + dstHostName = data[5] + smbVersion = data[6] + smbArch = data[7] + domainName = data[9] + auditAction = data[10] + auditStatus = data[11] + path = data[12] - data = {} - data["src_host"] = srcHost - data["src_port"] = "-1" - data["dst_host"] = dstHost - data["dst_port"] = 445 - data["logtype"] = self.logger.LOG_SMB_FILE_OPEN - data["logdata"] = { + log_entry = {} + log_entry["src_host"] = srcHost + log_entry["src_port"] = "-1" + log_entry["dst_host"] = dstHost + log_entry["dst_port"] = 445 + log_entry["logtype"] = self.logger.LOG_SMB_FILE_OPEN + log_entry["logdata"] = { "USER": user, "REMOTENAME": srcHostName, "SHARENAME": shareName, @@ -55,7 +76,7 @@ def handleLines(self, lines=None): "STATUS": auditStatus, "FILENAME": path, } - self.logger.log(data) + self.logger.log(log_entry) class CanarySamba(CanaryService): NAME = "smb" @@ -76,3 +97,6 @@ def startYourEngines(self, reactor=None): fs = SambaLogWatcher(logFile=self.audit_file, logger=self.logger) fs.start() + + # Alias for backward compatibility and explicit import in opencanary.tac + CanarySMB = CanarySamba