Skip to content

Commit

Permalink
Change to structure of NtlmAuthenticate
Browse files Browse the repository at this point in the history
Signed-off-by: Jeroen van Erp <[email protected]>
  • Loading branch information
hierynomus committed Jun 26, 2023
1 parent 900621d commit e648ab6
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 47 deletions.
1 change: 1 addition & 0 deletions src/it/docker-image/smb.conf
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ server string = %h server (Samba, Ubuntu)
dns proxy = no
interfaces = 192.168.2.0/24 eth0
bind interfaces only = yes
log level = 5
log file = /var/log/samba/log.%m
max log size = 1000
syslog = 0
Expand Down
67 changes: 33 additions & 34 deletions src/main/java/com/hierynomus/ntlm/messages/NtlmAuthenticate.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.hierynomus.protocol.commons.EnumWithValue;
import com.hierynomus.protocol.commons.buffer.Buffer;
import com.hierynomus.protocol.commons.buffer.Endian;
import com.hierynomus.protocol.commons.buffer.Buffer.PlainBuffer;

import static com.hierynomus.ntlm.messages.Utils.*;

Expand All @@ -37,13 +38,13 @@ public class NtlmAuthenticate extends NtlmMessage {
private byte[] domainName;
private byte[] workstation;
private byte[] encryptedRandomSessionKey;
private boolean useMic;
private byte[] mic;
private int baseMessageSize;

public NtlmAuthenticate(
byte[] lmResponse, byte[] ntResponse,
String userName, String domainName, String workstation,
byte[] encryptedRandomSessionKey, Set<NtlmNegotiateFlag> negotiateFlags,
byte[] encryptedRandomSessionKey, Set<NtlmNegotiateFlag> negotiateFlags,
WindowsVersion version) {
super(negotiateFlags, version);
this.lmResponse = ensureNotNull(lmResponse);
Expand All @@ -53,61 +54,59 @@ public NtlmAuthenticate(
this.workstation = ensureNotNull(workstation);
this.encryptedRandomSessionKey = ensureNotNull(encryptedRandomSessionKey);
this.negotiateFlags = negotiateFlags;
this.baseMessageSize = getBaseMessageSize();
}

@Override
public void write(Buffer.PlainBuffer buffer) {

writeAutentificateMessage(buffer);
private int getBaseMessageSize() {
int baseMessageSize = 64;
if (negotiateFlags.contains(NtlmNegotiateFlag.NTLMSSP_NEGOTIATE_VERSION) || mic != null) {
baseMessageSize += 8;
}

if (mic != null) {
// MIC (16 bytes) provided if in AvPairType is key MsvAvFlags with value & 0x00000002 is true
buffer.putRawBytes(mic);
baseMessageSize += 16;
}

// Payload
buffer.putRawBytes(lmResponse);
buffer.putRawBytes(ntResponse);
buffer.putRawBytes(domainName);
buffer.putRawBytes(userName);
buffer.putRawBytes(workstation);
buffer.putRawBytes(encryptedRandomSessionKey);
return baseMessageSize;
}

public void setMic(byte[] mic) {
this.mic = mic;
}
@Override
public void write(PlainBuffer buffer) {

public void writeAutentificateMessage(Buffer.PlainBuffer buffer) {
buffer.putString("NTLMSSP\0", Charsets.UTF_8); // Signature (8 bytes)
buffer.putUInt32(0x03); // MessageType (4 bytes)

int offset = 64; // for the offset

if (useMic) {
offset += 16;
}

if (negotiateFlags.contains(NtlmNegotiateFlag.NTLMSSP_NEGOTIATE_VERSION)) {
offset += 8;
}

int offset = baseMessageSize; // for the offset
offset = writeOffsettedByteArrayFields(buffer, lmResponse, offset); // LmChallengeResponseFields (8 bytes)
offset = writeOffsettedByteArrayFields(buffer, ntResponse, offset); // NtChallengeResponseFields (8 bytes)
offset = writeOffsettedByteArrayFields(buffer, domainName, offset); // DomainNameFields (8 bytes)
offset = writeOffsettedByteArrayFields(buffer, userName, offset); // UserNameFields (8 bytes)
offset = writeOffsettedByteArrayFields(buffer, workstation, offset); // WorkstationFields (8 bytes)
if (negotiateFlags.contains(NtlmNegotiateFlag.NTLMSSP_NEGOTIATE_KEY_EXCH)) {
offset = writeOffsettedByteArrayFields(buffer, encryptedRandomSessionKey, offset);
} else {
offset = writeOffsettedByteArrayFields(buffer, EMPTY, offset);
}
offset = writeOffsettedByteArrayFields(buffer, encryptedRandomSessionKey, offset); // EncryptedRandomSessionKeyFields (8 bytes)

buffer.putUInt32(EnumWithValue.EnumUtils.toLong(negotiateFlags)); // NegotiateFlags (4 bytes)

if (negotiateFlags.contains(NtlmNegotiateFlag.NTLMSSP_NEGOTIATE_VERSION)) {
buffer.putRawBytes(getVersion()); // Version (8 bytes)
} else if (mic != null) {
buffer.putUInt64(0L); // If the MIC is present, the Version field MUST be present.
}

if (mic != null) {
buffer.putRawBytes(mic, 0, 16); // MIC (16 bytes)
}

// Payload
buffer.putRawBytes(lmResponse);
buffer.putRawBytes(ntResponse);
buffer.putRawBytes(domainName);
buffer.putRawBytes(userName);
buffer.putRawBytes(workstation);
buffer.putRawBytes(encryptedRandomSessionKey);
}

public void setMic(byte[] mic) {
this.mic = mic;
}

/**
Expand Down
27 changes: 15 additions & 12 deletions src/main/java/com/hierynomus/smbj/auth/NtlmAuthenticator.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
import org.slf4j.LoggerFactory;

import com.hierynomus.asn1.types.primitive.ASN1ObjectIdentifier;
import com.hierynomus.msdtyp.MsDataTypes;
import com.hierynomus.msdtyp.FileTime;
import com.hierynomus.ntlm.NtlmConfig;
import com.hierynomus.ntlm.NtlmException;
import com.hierynomus.ntlm.av.AvId;
Expand Down Expand Up @@ -148,12 +148,14 @@ private AuthenticateResponse doNegotiate(AuthenticationContext context, byte[] g
this.negotiateFlags.add(NTLMSSP_NEGOTIATE_ANONYMOUS);
}

if (Strings.isNotBlank(context.getDomain())) {
this.negotiateFlags.add(NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED);
}
if (!this.negotiateFlags.contains(NtlmNegotiateFlag.NTLMSSP_NEGOTIATE_VERSION)) {
if (Strings.isNotBlank(context.getDomain())) {
this.negotiateFlags.add(NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED);
}

if (Strings.isNotBlank(config.getWorkstationName())) {
this.negotiateFlags.add(NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED);
if (Strings.isNotBlank(config.getWorkstationName())) {
this.negotiateFlags.add(NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED);
}
}

this.negotiateMessage = new NtlmNegotiate(negotiateFlags, context.getDomain(), config.getWorkstationName(), config.getWindowsVersion(), config.isOmitVersion());
Expand All @@ -172,7 +174,7 @@ private AuthenticateResponse doAuthenticate(AuthenticationContext context, NtlmC
// [MS-NLMP] 3.2.2 -- Special case for anonymous authentication
if (context.isAnonymous()) {
NtlmAuthenticate msg = new NtlmAuthenticate(null, null, context.getUsername(), context.getDomain(),
config.getWorkstationName(), null, negotiateFlags, config.getWindowsVersion());
config.getWorkstationName(), null, negotiateFlags, config.getWindowsVersion());
response.setNegToken(negTokenTarg(msg));
return response;
}
Expand All @@ -181,9 +183,9 @@ private AuthenticateResponse doAuthenticate(AuthenticationContext context, NtlmC
negotiateFlags.add(NTLMSSP_NEGOTIATE_TARGET_INFO);
TargetInfo clientTargetInfo = createClientTargetInfo(serverNtlmChallenge);

ComputedNtlmV2Response computedNtlmV2Response = functions.computeResponse(context.getUsername(),
context.getDomain(), context.getPassword(), serverNtlmChallenge, MsDataTypes.nowAsFileTime(),
clientTargetInfo);
long time = FileTime.now().getWindowsTimeStamp();
ComputedNtlmV2Response computedNtlmV2Response = functions.computeResponse(context.getUsername(), context.getDomain(), context.getPassword(), serverNtlmChallenge, time, clientTargetInfo);

byte[] sessionBaseKey = computedNtlmV2Response.getSessionBaseKey();
byte[] ntResponse = computedNtlmV2Response.getNtResponse();
byte[] lmResponse = new byte[0]; // computedNtlmV2Response.getLmResponse();
Expand All @@ -195,7 +197,7 @@ private AuthenticateResponse doAuthenticate(AuthenticationContext context, NtlmC
if (serverFlags.contains(NTLMSSP_NEGOTIATE_KEY_EXCH) && (serverFlags.contains(NTLMSSP_NEGOTIATE_SEAL) || serverFlags.contains(NTLMSSP_NEGOTIATE_SIGN) || serverFlags.contains(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))) {
exportedSessionKey = new byte[16];
random.nextBytes(exportedSessionKey);
encryptedRandomSessionKey = NtlmFunctions.rc4k(securityProvider, sessionBaseKey, exportedSessionKey);
encryptedRandomSessionKey = NtlmFunctions.rc4k(securityProvider, keyExchangeKey, exportedSessionKey);
} else {
exportedSessionKey = keyExchangeKey;
encryptedRandomSessionKey = exportedSessionKey; // TODO
Expand All @@ -210,11 +212,12 @@ private AuthenticateResponse doAuthenticate(AuthenticationContext context, NtlmC
AvPairFlags pair = serverNtlmChallenge.getTargetInfo() != null ? serverNtlmChallenge.getTargetInfo().getAvPair(AvId.MsvAvFlags) : null;
if (pair != null && (pair.getValue() & 0x00000002) > 0) {
// Calculate MIC
msg.setMic(new byte[16]);
// TODO correct hash should be tested
Buffer.PlainBuffer micBuffer = new Buffer.PlainBuffer(Endian.LE);
negotiateMessage.write(micBuffer); // negotiateMessage
micBuffer.putRawBytes(serverNtlmChallenge.getServerChallenge()); // challengeMessage
msg.writeAutentificateMessage(micBuffer); // authentificateMessage
msg.write(micBuffer); // authentificateMessage

byte[] mic = NtlmFunctions.hmac_md5(securityProvider, sessionBaseKey, micBuffer.getCompactData());
msg.setMic(mic);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import static com.hierynomus.ntlm.messages.NtlmNegotiateFlag.NTLMSSP_NEGOTIATE_N
import static com.hierynomus.ntlm.messages.NtlmNegotiateFlag.NTLMSSP_NEGOTIATE_SIGN
import static com.hierynomus.ntlm.messages.NtlmNegotiateFlag.NTLMSSP_NEGOTIATE_TARGET_INFO
import static com.hierynomus.ntlm.messages.NtlmNegotiateFlag.NTLMSSP_NEGOTIATE_UNICODE
import static com.hierynomus.ntlm.messages.NtlmNegotiateFlag.NTLMSSP_NEGOTIATE_VERSION
import static com.hierynomus.ntlm.messages.NtlmNegotiateFlag.NTLMSSP_REQUEST_TARGET
import static com.hierynomus.ntlm.messages.WindowsVersion.NtlmRevisionCurrent.NTLMSSP_REVISION_W2K3
import static com.hierynomus.ntlm.messages.WindowsVersion.ProductMajorVersion.WINDOWS_MAJOR_VERSION_6
Expand Down

0 comments on commit e648ab6

Please sign in to comment.