Discussion:
[PATCH 1/7] cifs: Bypass windows extended security for ntlmv2 negotiate
Namjae Jeon
2014-08-20 10:39:01 UTC
Permalink
Windows machine has extended security feature which refuse to allow
authentication when there is time difference between server time and
client time when ntlmv2 negotiation is used. This problem is prevalent
in embedded enviornment where system time is set to default 1970.

We don't know yet the exact threshold for the time difference at which
the connection is refused but one comment in cifs code suggest that it
is around 5 minutes.

This patch tries to solve this problem by sending the received server
time during negotiate process as the current client time.

Signed-off-by: Namjae Jeon <namjae.jeon-***@public.gmane.org>
Signed-off-by: Ashish Sangwan <a.sangwan-***@public.gmane.org>
---
fs/cifs/cifsencrypt.c | 4 ++--
fs/cifs/cifsglob.h | 2 ++
fs/cifs/cifssmb.c | 2 ++
fs/cifs/smb2pdu.c | 1 +
4 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
index 4934347..d5cec81 100644
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -671,8 +671,8 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
(ses->auth_key.response + CIFS_SESS_KEY_SIZE);
ntlmv2->blob_signature = cpu_to_le32(0x00000101);
ntlmv2->reserved = 0;
- /* Must be within 5 minutes of the server */
- ntlmv2->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
+ /* Hack to get around windows extended security */
+ ntlmv2->time = cpu_to_le64(ses->serverTime);
get_random_bytes(&ntlmv2->client_chal, sizeof(ntlmv2->client_chal));
ntlmv2->reserved2 = 0;

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index ce24c1f..9344c94 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -796,6 +796,8 @@ struct cifs_ses {
enum securityEnum sectype; /* what security flavor was specified? */
bool sign; /* is signing required? */
bool need_reconnect:1; /* connection reset, uid now invalid */
+ __u64 serverTime; /* Keeps a track of server time sent by server
+ during negotiate response */
#ifdef CONFIG_CIFS_SMB2
__u16 session_flags;
char smb3signingkey[SMB3_SIGN_KEY_SIZE]; /* for signing smb3 packets */
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 86a2aa5..ead2da0 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -584,6 +584,8 @@ CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
if (rc != 0)
goto neg_err_exit;

+ ses->serverTime = le32_to_cpu(pSMBr->SystemTimeLow);
+ ses->serverTime |= ((__u64)le32_to_cpu(pSMBr->SystemTimeHigh) << 32);
server->dialect = le16_to_cpu(pSMBr->DialectIndex);
cifs_dbg(FYI, "Dialect: %d\n", server->dialect);
/* Check wct = 1 error case */
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index ed42234..a40f492 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -381,6 +381,7 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
if (rc != 0)
goto neg_exit;

+ ses->serverTime = le64_to_cpu(rsp->SystemTime);
cifs_dbg(FYI, "mode 0x%x\n", rsp->SecurityMode);

/* BB we may eventually want to match the negotiated vs. requested
--
1.7.7
Steve French
2014-08-21 04:51:02 UTC
Permalink
This is an unusual sounding issue. Any comments on this from the auth experts?

Seems better to investigate this more if we end up enforcing a "must
be within 5 minutes" threshold instead of this patch. Have we done a
dochelp on this before?


---------- Forwarded message ----------
From: Namjae Jeon <namjae.jeon-***@public.gmane.org>
Date: Wed, Aug 20, 2014 at 5:39 AM
Subject: [PATCH 1/7] cifs: Bypass windows extended security for ntlmv2 negotiate
To: Steve French <smfrench-***@public.gmane.org>
Cc: Shirish Pargaonkar <shirishpargaonkar-***@public.gmane.org>, Pavel Shilovsky
<pshilovsky-***@public.gmane.org>, linux-cifs-***@public.gmane.org, Ashish Sangwan
<a.sangwan-***@public.gmane.org>


Windows machine has extended security feature which refuse to allow
authentication when there is time difference between server time and
client time when ntlmv2 negotiation is used. This problem is prevalent
in embedded enviornment where system time is set to default 1970.

We don't know yet the exact threshold for the time difference at which
the connection is refused but one comment in cifs code suggest that it
is around 5 minutes.

This patch tries to solve this problem by sending the received server
time during negotiate process as the current client time.

Signed-off-by: Namjae Jeon <namjae.jeon-***@public.gmane.org>
Signed-off-by: Ashish Sangwan <a.sangwan-***@public.gmane.org>
---
fs/cifs/cifsencrypt.c | 4 ++--
fs/cifs/cifsglob.h | 2 ++
fs/cifs/cifssmb.c | 2 ++
fs/cifs/smb2pdu.c | 1 +
4 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
index 4934347..d5cec81 100644
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -671,8 +671,8 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const
struct nls_table *nls_cp)
(ses->auth_key.response + CIFS_SESS_KEY_SIZE);
ntlmv2->blob_signature = cpu_to_le32(0x00000101);
ntlmv2->reserved = 0;
- /* Must be within 5 minutes of the server */
- ntlmv2->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
+ /* Hack to get around windows extended security */
+ ntlmv2->time = cpu_to_le64(ses->serverTime);
get_random_bytes(&ntlmv2->client_chal, sizeof(ntlmv2->client_chal));
ntlmv2->reserved2 = 0;

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index ce24c1f..9344c94 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -796,6 +796,8 @@ struct cifs_ses {
enum securityEnum sectype; /* what security flavor was specified? */
bool sign; /* is signing required? */
bool need_reconnect:1; /* connection reset, uid now invalid */
+ __u64 serverTime; /* Keeps a track of server time sent by server
+ during negotiate response */
#ifdef CONFIG_CIFS_SMB2
__u16 session_flags;
char smb3signingkey[SMB3_SIGN_KEY_SIZE]; /* for signing smb3 packets */
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 86a2aa5..ead2da0 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -584,6 +584,8 @@ CIFSSMBNegotiate(const unsigned int xid, struct
cifs_ses *ses)
if (rc != 0)
goto neg_err_exit;

+ ses->serverTime = le32_to_cpu(pSMBr->SystemTimeLow);
+ ses->serverTime |= ((__u64)le32_to_cpu(pSMBr->SystemTimeHigh) << 32);
server->dialect = le16_to_cpu(pSMBr->DialectIndex);
cifs_dbg(FYI, "Dialect: %d\n", server->dialect);
/* Check wct = 1 error case */
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index ed42234..a40f492 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -381,6 +381,7 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
if (rc != 0)
goto neg_exit;

+ ses->serverTime = le64_to_cpu(rsp->SystemTime);
cifs_dbg(FYI, "mode 0x%x\n", rsp->SecurityMode);

/* BB we may eventually want to match the negotiated vs. requested
--
1.7.7
--
Thanks,

Steve
Andrew Bartlett
2014-08-22 02:32:22 UTC
Permalink
Post by Steve French
This is an unusual sounding issue. Any comments on this from the auth experts?
Seems better to investigate this more if we end up enforcing a "must
be within 5 minutes" threshold instead of this patch. Have we done a
dochelp on this before?
I am certainly nervous about this patch, as I've not ever seen this
before. The thing that makes me feel particularly odd about this is
that: In general, NTLMSSP clients don't have the server's time, and
certainly don't have the domain controller's time. (That CIFS provides
this does not mean we should use it, NTLMSSP is a general protocol and
adding CIFS-specific hacks indicates we are understanding it wrong, in
my experience).

BTW, the domain controller is the only element here that could check the
embedded time, but I'll grant that typically servers are better in sync
with each other than this embedded device might be.

The 5 mins stuff probably refers to Kerberos, which does have such a
time limit. I've never seen NTLMSSP fail against windows due to clock
skew.

I would like to see much more investigation here before this is done,
because if you just trust the server's time and if you need to, to pass
a security check, you override that check. We need to understand why it
is in place.

Thanks,

Andrew Bartlett
--
Andrew Bartlett
http://samba.org/~abartlet/
Authentication Developer, Samba Team http://samba.org
Samba Developer, Catalyst IT http://catalyst.net.nz/services/samba
Simo
2014-08-22 04:17:27 UTC
Permalink
Post by Andrew Bartlett
Post by Steve French
This is an unusual sounding issue. Any comments on this from the auth experts?
Seems better to investigate this more if we end up enforcing a "must
be within 5 minutes" threshold instead of this patch. Have we done a
dochelp on this before?
I am certainly nervous about this patch, as I've not ever seen this
before. The thing that makes me feel particularly odd about this is
that: In general, NTLMSSP clients don't have the server's time,
This is simply false.
Modern servers send the server timestamp in the TargetInfo Av_Pair
structure in the challenge message [see MS-NLMP 2.2.2.1].

In [MS-NLMP 3.1.5.1.2] it is explicitly mentioned that the client must
use the provided (from the server) timestamp if present or current time
if it is not.

Not only a modern server *should* send a timestamp, but a modern client,
on seeing that a timestamp is available should provide a MIC in the
Authentication message [MS-NLMP 3.1.5.1.2].

Unfortunately samba at the moment has a very limited and incomplete
implementation of the NTLM protocol and doesn't do much with targetinfo
except mocking it up a little.

An implementation that is very close to implementing all of the MS-NLMP
specification is here:
https://git.samba.org/?p=idra/gss-ntlmssp.git;a=summary
or here: https://fedorahosted.org/gss-ntlmssp/
and I hope to make samba use it eventually, when we have a more decent
set of interfaces to connect to DCs (the current winbind interfacing is
suboptimal but fixable).
Post by Andrew Bartlett
and certainly don't have the domain controller's time.
This is true but not a problem today were servers are supposed to have
the time in sync with the KDC/Domain Controller anyway.
Post by Andrew Bartlett
(That CIFS provides
this does not mean we should use it, NTLMSSP is a general protocol and
adding CIFS-specific hacks indicates we are understanding it wrong, in
my experience).
BTW, the domain controller is the only element here that could check the
embedded time, but I'll grant that typically servers are better in sync
with each other than this embedded device might be.
The 5 mins stuff probably refers to Kerberos, which does have such a
time limit. I've never seen NTLMSSP fail against windows due to clock
skew.
That's becasue a client is supposed to use the time provided by the
server, so no clockskew is really possible,
Post by Andrew Bartlett
I would like to see much more investigation here before this is done,
because if you just trust the server's time and if you need to, to pass
a security check, you override that check. We need to understand why it
is in place.
Sorry but this makes no sense, if you can bypass a "security mechanism"
in the client, then there is *no* security mechanism.

The reason why a timestamp is provided by the server is (most probably)
to mitigate replay attacks when the client uses a MIC (as it should)
when the timestamp is provided.

Simo.
Stefan (metze) Metzmacher
2014-08-22 07:12:43 UTC
Permalink
Post by Simo
Post by Andrew Bartlett
Post by Steve French
This is an unusual sounding issue. Any comments on this from the auth experts?
Seems better to investigate this more if we end up enforcing a "must
be within 5 minutes" threshold instead of this patch. Have we done a
dochelp on this before?
I am certainly nervous about this patch, as I've not ever seen this
before. The thing that makes me feel particularly odd about this is
that: In general, NTLMSSP clients don't have the server's time,
This is simply false.
Modern servers send the server timestamp in the TargetInfo Av_Pair
structure in the challenge message [see MS-NLMP 2.2.2.1].
In [MS-NLMP 3.1.5.1.2] it is explicitly mentioned that the client must
use the provided (from the server) timestamp if present or current time
if it is not.
I talks about the MsvAvTimestamp from CHALLENGE_MESSAGE.TargetInfo.Value
not the timestamp from smb negprot.

I think it would make sense to skip the timestamp if the client doesn't
find the server time in CHALLENGE_MESSAGE.TargetInfo.Value
and notices that the local time isn't correct. E.g. the date is
before the year 2000.

metze
Simo
2014-08-22 12:30:08 UTC
Permalink
Post by Stefan (metze) Metzmacher
Post by Simo
Post by Andrew Bartlett
Post by Steve French
This is an unusual sounding issue. Any comments on this from the auth experts?
Seems better to investigate this more if we end up enforcing a "must
be within 5 minutes" threshold instead of this patch. Have we done a
dochelp on this before?
I am certainly nervous about this patch, as I've not ever seen this
before. The thing that makes me feel particularly odd about this is
that: In general, NTLMSSP clients don't have the server's time,
This is simply false.
Modern servers send the server timestamp in the TargetInfo Av_Pair
structure in the challenge message [see MS-NLMP 2.2.2.1].
In [MS-NLMP 3.1.5.1.2] it is explicitly mentioned that the client must
use the provided (from the server) timestamp if present or current time
if it is not.
I talks about the MsvAvTimestamp from CHALLENGE_MESSAGE.TargetInfo.Value
not the timestamp from smb negprot.
Sure, the point is that the server *does* send a timestamp that the
client is supposed to use.
Post by Stefan (metze) Metzmacher
I think it would make sense to skip the timestamp if the client doesn't
find the server time in CHALLENGE_MESSAGE.TargetInfo.Value
and notices that the local time isn't correct. E.g. the date is
before the year 2000.
IT probably shouldn't use the timestamp at all if the challenge message
does not have it because it means the server doesn't know what to do
about it anyway.
However using the timestamp found in the smb packet is as good as
anything else, it won't hurt anything, unless the server has its time
completely off and relay the authentication to a DC while the client had
the clock right.

Simo.

Jeremy Allison
2014-08-22 03:41:21 UTC
Permalink
Post by Steve French
This is an unusual sounding issue. Any comments on this from the auth experts?
Seems better to investigate this more if we end up enforcing a "must
be within 5 minutes" threshold instead of this patch. Have we done a
dochelp on this before?
No we have not. I'd feel happier if you could
add some test code to smbtorture that showed
NTLM authentication succeeding with correct time,
and it failing with a large time drift, that
passes against a Windows server.

Jeremy.
Simo
2014-08-22 04:27:06 UTC
Permalink
Post by Namjae Jeon
Windows machine has extended security feature which refuse to allow
authentication when there is time difference between server time and
client time when ntlmv2 negotiation is used. This problem is prevalent
in embedded enviornment where system time is set to default 1970.
We don't know yet the exact threshold for the time difference at which
the connection is refused but one comment in cifs code suggest that it
is around 5 minutes.
This patch tries to solve this problem by sending the received server
time during negotiate process as the current client time.
---
fs/cifs/cifsencrypt.c | 4 ++--
fs/cifs/cifsglob.h | 2 ++
fs/cifs/cifssmb.c | 2 ++
fs/cifs/smb2pdu.c | 1 +
4 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
index 4934347..d5cec81 100644
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -671,8 +671,8 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
(ses->auth_key.response + CIFS_SESS_KEY_SIZE);
ntlmv2->blob_signature = cpu_to_le32(0x00000101);
ntlmv2->reserved = 0;
- /* Must be within 5 minutes of the server */
- ntlmv2->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
+ /* Hack to get around windows extended security */
+ ntlmv2->time = cpu_to_le64(ses->serverTime);
get_random_bytes(&ntlmv2->client_chal, sizeof(ntlmv2->client_chal));
ntlmv2->reserved2 = 0;
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index ce24c1f..9344c94 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -796,6 +796,8 @@ struct cifs_ses {
enum securityEnum sectype; /* what security flavor was specified? */
bool sign; /* is signing required? */
bool need_reconnect:1; /* connection reset, uid now invalid */
+ __u64 serverTime; /* Keeps a track of server time sent by server
+ during negotiate response */
#ifdef CONFIG_CIFS_SMB2
__u16 session_flags;
char smb3signingkey[SMB3_SIGN_KEY_SIZE]; /* for signing smb3 packets */
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 86a2aa5..ead2da0 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -584,6 +584,8 @@ CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
if (rc != 0)
goto neg_err_exit;
+ ses->serverTime = le32_to_cpu(pSMBr->SystemTimeLow);
+ ses->serverTime |= ((__u64)le32_to_cpu(pSMBr->SystemTimeHigh) << 32);
server->dialect = le16_to_cpu(pSMBr->DialectIndex);
cifs_dbg(FYI, "Dialect: %d\n", server->dialect);
/* Check wct = 1 error case */
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index ed42234..a40f492 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -381,6 +381,7 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
if (rc != 0)
goto neg_exit;
+ ses->serverTime = le64_to_cpu(rsp->SystemTime);
cifs_dbg(FYI, "mode 0x%x\n", rsp->SecurityMode);
/* BB we may eventually want to match the negotiated vs. requested
This patch is not addressing the problem in the correct way.
The server should send the time in the challenge message targetinfo data
(see MS-NLMP and search for MsvAvTimestamp in 2.2.2.1 and 3..5.1.2),
only if it is not available the currentime should be used (if you have
to pick the current time I guess you can employ tricks to try to get one
as close as possible to the server time by other means).

It is not clear to me whether the code parses the challenge messages's
targetinfo field, if it doesn't it should.

Simo.
Namjae Jeon
2014-08-22 07:07:29 UTC
Permalink
Post by Simo
This patch is not addressing the problem in the correct way.
The server should send the time in the challenge message targetinfo data
(see MS-NLMP and search for MsvAvTimestamp in 2.2.2.1 and 3..5.1.2),
only if it is not available the currentime should be used (if you have
to pick the current time I guess you can employ tricks to try to get one
as close as possible to the server time by other means).
It is not clear to me whether the code parses the challenge messages's
targetinfo field, if it doesn't it should.
Okay, I will check your point.

Thanks for your reply :)
Post by Simo
Simo.
Loading...