diff --git a/src/analyzer/protocol/smb/smb-time.pac b/src/analyzer/protocol/smb/smb-time.pac index d30a151ce1..a4fcd01dc1 100644 --- a/src/analyzer/protocol/smb/smb-time.pac +++ b/src/analyzer/protocol/smb/smb-time.pac @@ -1,6 +1,6 @@ %header{ double filetime2zeektime(uint64_t ts); -double time_from_lanman(SMB_time* t, SMB_date* d, uint16_t tz); +double time_from_lanman(uint32_t smb_time, uint32_t smb_date, uint16_t tz); zeek::RecordValPtr SMB_BuildMACTimes(uint64_t modify, uint64_t access, uint64_t create, uint64_t change); @@ -14,17 +14,30 @@ double filetime2zeektime(uint64_t ts) return (static_cast(ts) / 10000000.0) - 11644473600.0; } -double time_from_lanman(SMB_time* t, SMB_date* d, uint16_t tz) +double time_from_lanman(uint32_t smb_time, uint32_t smb_date, uint16_t tz) { - tm lTime; - lTime.tm_sec = ${t.two_seconds} * 2; - lTime.tm_min = ${t.minutes}; - lTime.tm_hour = ${t.hours}; - lTime.tm_mday = ${d.day}; - lTime.tm_mon = ${d.month}; - lTime.tm_year = 1980 + ${d.year}; + tm lTime{0}; + + // Lanman uses this format for time/date: + // https://learn.microsoft.com/en-us/cpp/c-runtime-library/32-bit-windows-time-date-formats + // Seconds is in 2-second increments in the data. + lTime.tm_sec = (smb_time & 0x1f) * 2; + lTime.tm_min = (smb_time >> 5) & 0x3f; + lTime.tm_hour = (smb_time >> 11) & 0x1f; + + lTime.tm_mday = smb_date & 0x1f; + // tm_mon is zero-indexed, so adjust for that. + lTime.tm_mon = ((smb_date >> 5) & 0x0f) - 1; + // The year in the data is the number of years from 1980, while tm_year is the + // number of years since 1900. + lTime.tm_year = ((smb_date >> 9) & 0x7f) + 80; lTime.tm_isdst = -1; - return mktime(&lTime) + tz; + + // The timezone passed in the data is the number of minutes from UTC, while + // tm_gmtoff is the number of seconds east of UTC. Adjust for that. + lTime.tm_gmtoff = static_cast(tz) * 60; + + return timegm(&lTime); } zeek::RecordValPtr SMB_BuildMACTimes(uint64_t modify, uint64_t access, @@ -45,15 +58,3 @@ zeek::RecordValPtr SMB_BuildMACTimes(uint64_t modify, uint64_t access, type SMB_timestamp32 = uint32; type SMB_timestamp = uint64; - -type SMB_time = record { - two_seconds : uint16; - minutes : uint16; - hours : uint16; -} &byteorder = littleendian; - -type SMB_date = record { - day : uint16; - month : uint16; - year : uint16; -} &byteorder = littleendian; diff --git a/src/analyzer/protocol/smb/smb1-com-negotiate.pac b/src/analyzer/protocol/smb/smb1-com-negotiate.pac index 57529a507f..9f2828b601 100644 --- a/src/analyzer/protocol/smb/smb1-com-negotiate.pac +++ b/src/analyzer/protocol/smb/smb1-com-negotiate.pac @@ -181,8 +181,8 @@ type SMB1_negotiate_lanman_response(header: SMB_Header) = record { max_number_vcs : uint16; raw_mode : uint16; # expanded in &let session_key : uint32; - server_time : SMB_time; - server_date : SMB_date; + server_time : uint16; + server_date : uint16; server_tz : uint16; encryption_key_length : uint16; reserved : uint16; # must be zero diff --git a/src/analyzer/protocol/smb/smb1-com-query-information.pac b/src/analyzer/protocol/smb/smb1-com-query-information.pac index b3016bfb65..17329b8af3 100644 --- a/src/analyzer/protocol/smb/smb1-com-query-information.pac +++ b/src/analyzer/protocol/smb/smb1-com-query-information.pac @@ -31,7 +31,7 @@ type SMB1_query_information_request(header: SMB_Header) = record { type SMB1_query_information_response(header: SMB_Header) = record { word_count : uint8; file_attribs : uint16; - last_write_time : SMB_time; + last_write_time : uint32; file_size : uint32; reserved : uint16[5]; byte_count : uint16; diff --git a/testing/btest/Baseline/scripts.base.protocols.smb.smb1-negotiate-lanman/out b/testing/btest/Baseline/scripts.base.protocols.smb.smb1-negotiate-lanman/out new file mode 100644 index 0000000000..b407cefc71 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.smb.smb1-negotiate-lanman/out @@ -0,0 +1,8 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +smb1_negotiate_request +[command=114, status=0, flags=24, flags2=51283, tid=0, pid=4660, uid=0, mid=1] +[PC NETWORK PROGRAM 1.0, LANMAN1.0, LM1.2X002, LANMAN2.1] +smb1_negotiate_response +[command=114, status=0, flags=152, flags2=51283, tid=0, pid=4660, uid=0, mid=1] +[core=, lanman=[word_count=13, dialect_index=3, security_mode=[user_level=T, challenge_response=T, signatures_enabled=, signatures_required=], max_buffer_size=4356, max_mpx_count=32, max_number_vcs=1, raw_mode=[read_raw=F, write_raw=F], session_key=0, server_time=1758862898.0, encryption_key=\x11"3DUfw\x88, primary_domain=\xe4\xbd\x97\xe4\xad\x92\xe5\x89\x87\xe5\x95\x8fP], ntlm=] +Parsed Response Server Time: 2025-09-26-05:01:38T diff --git a/testing/btest/Traces/README b/testing/btest/Traces/README index a01d06902b..f2389909f5 100644 --- a/testing/btest/Traces/README +++ b/testing/btest/Traces/README @@ -56,3 +56,6 @@ Trace Index/Sources: - smb_v2_only_non_zero_reserved1.pcap Provided by @predator89090 on #4730 https://github.com/zeek/zeek/issues/4730 +- smb/cifs_negotiate_lanman.pcap + Generated with scapy/chatgpt by @Mohan-Dhawan + https://github.com/zeek/zeek/issues/4545 \ No newline at end of file diff --git a/testing/btest/Traces/smb/cifs_negotiate_lanman.pcap b/testing/btest/Traces/smb/cifs_negotiate_lanman.pcap new file mode 100644 index 0000000000..fffaa573ca Binary files /dev/null and b/testing/btest/Traces/smb/cifs_negotiate_lanman.pcap differ diff --git a/testing/btest/scripts/base/protocols/smb/smb1-negotiate-lanman.zeek b/testing/btest/scripts/base/protocols/smb/smb1-negotiate-lanman.zeek new file mode 100644 index 0000000000..aefacc2ae0 --- /dev/null +++ b/testing/btest/scripts/base/protocols/smb/smb1-negotiate-lanman.zeek @@ -0,0 +1,19 @@ +# @TEST-DOC: Tests parsing of SMB1 Negotiate Request/Response LanMan messages. Primarily exists to test parsing of the timetstamps. +# +# @TEST-EXEC: zeek -r ${TRACES}/smb/cifs_negotiate_lanman.pcap %INPUT > out +# @TEST-EXEC: TEST_DIFF_CANONIFIER= btest-diff out + +event smb1_negotiate_request(c: connection, hdr: SMB1::Header, dialects: string_vec) + { + print "smb1_negotiate_request"; + print hdr; + print dialects; + } + +event smb1_negotiate_response(c: connection, hdr: SMB1::Header, response: SMB1::NegotiateResponse) + { + print "smb1_negotiate_response"; + print hdr; + print response; + print fmt("Parsed Response Server Time: %DT", response$lanman$server_time); + }