Something went wrong. Try again.
This repository has no description
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326/** * SMB2 Session Setup Command Handler * Handles SMB2_SESSION_SETUP requests and responses */
import type { SMB2Connection, SMB2Session, SMB2TreeConnect, SMB2SessionSetupRequest, SMB2SessionSetupResponse, SMB2ServerConfig, SMB2CommandHandler,} from '../protocol/types.js';import { SMB2_STATUS, SMB2_HEADER_SIZE, SMB2_COMMANDS,} from '../protocol/constants.js';import { SMB2MessageParser } from '../protocol/parser.js';import { SMB2MessageSerializer } from '../protocol/serializer.js';import { SMB2AuthenticationManager } from '../auth/authentication.js';import { Logger } from '../utils/logger.js';
export class SMB2SessionSetupHandler { private readonly authManager: SMB2AuthenticationManager; private readonly parser: SMB2MessageParser; private readonly serializer: SMB2MessageSerializer; private readonly logger: Logger;
constructor(authManager: SMB2AuthenticationManager) { this.authManager = authManager; this.parser = new SMB2MessageParser(); this.serializer = new SMB2MessageSerializer(); this.logger = new Logger('SMB2SessionSetupHandler'); }
public async handle( requestData: Buffer, connection: SMB2Connection, session?: SMB2Session, _treeConnect?: SMB2TreeConnect, ): Promise<Buffer> { try { // Parse the session setup request const parseResult = this.parser.parseSessionSetupRequest(requestData); const request = parseResult.result;
this.logger.debug(`Session setup request from ${connection.clientAddress}:`); this.logger.debug(` Flags: 0x${request.flags.toString(16)}`); this.logger.debug(` Security mode: 0x${request.securityMode.toString(16)}`); this.logger.debug(` Capabilities: 0x${request.capabilities.toString(16)}`); this.logger.debug(` Security buffer length: ${request.securityBufferLength}`); this.logger.debug(` Previous session ID: ${request.previousSessionId}`);
// Handle different authentication types based on security buffer let authResult; if (request.securityBufferLength === 0) { // Anonymous authentication this.logger.debug('Attempting anonymous authentication'); authResult = await this.authManager.authenticateUser('', '', connection); } else { // Parse security buffer for authentication type const securityBuffer = request.securityBuffer; if (this.isNTLMToken(securityBuffer)) { // NTLM authentication this.logger.debug('Attempting NTLM authentication'); authResult = await this.authManager.authenticateNTLM(securityBuffer, connection); } else if (this.isKerberosToken(securityBuffer)) { // Kerberos authentication (not implemented) this.logger.warn('Kerberos authentication not implemented, falling back to guest'); authResult = await this.authManager.authenticateUser('guest', '', connection); } else { // Unknown security buffer, try guest authentication this.logger.warn('Unknown security buffer format, falling back to guest'); authResult = await this.authManager.authenticateUser('guest', '', connection); } }
if (!authResult.success) { this.logger.warn(`Authentication failed: ${authResult.error}`); throw new Error('Authentication failed'); }
// Create or update session let sessionId: bigint; let isNewSession = false;
if (request.previousSessionId !== 0n && session) { // Continuing existing session sessionId = session.sessionId; this.logger.debug(`Continuing existing session: ${sessionId}`); } else { // Create new session sessionId = this.generateSessionId(); isNewSession = true; this.logger.debug(`Creating new session: ${sessionId}`); }
// Create security context const securityContext = this.authManager.createSecurityContext(sessionId, authResult);
// Create session object if new if (isNewSession) { const newSession: SMB2Session = { sessionId, userId: authResult.userId || 'anonymous', isGuest: authResult.isGuest, isAnonymous: authResult.isAnonymous, creationTime: new Date(), lastActivityTime: new Date(), signingRequired: connection.requireMessageSigning && !authResult.isAnonymous, encryptionRequired: false, // TODO: Implement encryption requirements preauthIntegrityHashValue: Buffer.alloc(64), // TODO: Implement preauth integrity sessionKey: securityContext.sessionKey, signKey: securityContext.signKey, applicationKey: securityContext.applicationKey, };
// Add session to connection connection.sessions.set(sessionId, newSession); }
// Determine session flags let sessionFlags = 0; if (authResult.isGuest) { sessionFlags |= 0x0001; // SMB2_SESSION_FLAG_IS_GUEST } if (authResult.isAnonymous) { sessionFlags |= 0x0002; // SMB2_SESSION_FLAG_IS_NULL }
// Create response security buffer (empty for now) const responseSecurityBuffer = this.createResponseSecurityBuffer(authResult);
// Create session setup response const response: SMB2SessionSetupResponse = { structureSize: 9, sessionFlags, securityBufferOffset: responseSecurityBuffer.length > 0 ? SMB2_HEADER_SIZE + 9 : 0, securityBufferLength: responseSecurityBuffer.length, securityBuffer: responseSecurityBuffer, };
// Serialize the response const responseBuffer = this.serializer.serializeSessionSetupResponse(response);
this.logger.info(`Session setup successful for user: ${authResult.userId} (Session ID: ${sessionId})`); return responseBuffer;
} catch (error) { this.logger.error('Error handling session setup request:', error); throw error; } }
/** * Generate a unique session ID */ private generateSessionId(): bigint { // Generate a random 64-bit session ID // In practice, this should be unique across all sessions return BigInt(Math.floor(Math.random() * Number.MAX_SAFE_INTEGER)) + 1n; }
/** * Check if security buffer contains NTLM token */ private isNTLMToken(buffer: Buffer): boolean { if (buffer.length < 8) { return false; }
// Check for NTLM signature "NTLMSSP\0" const ntlmSignature = Buffer.from('NTLMSSP\0', 'ascii'); return buffer.subarray(0, 8).equals(ntlmSignature); }
/** * Check if security buffer contains Kerberos token */ private isKerberosToken(buffer: Buffer): boolean { if (buffer.length < 2) { return false; }
// Check for SPNEGO/Kerberos ASN.1 DER encoding // This is a simplified check - real implementation would be more comprehensive return buffer[0] === 0x60; // ASN.1 APPLICATION tag }
/** * Create response security buffer */ private createResponseSecurityBuffer(authResult: any): Buffer { // For anonymous and guest authentication, return empty buffer if (authResult.isAnonymous || authResult.isGuest) { return Buffer.alloc(0); }
// For NTLM authentication, would return NTLM Type 2 or Type 3 message // For now, return empty buffer return Buffer.alloc(0); }
/** * Parse NTLM Type 1 message */ private parseNTLMType1(buffer: Buffer): any { // Stub implementation - would parse NTLM Type 1 message structure if (buffer.length < 32) { throw new Error('Invalid NTLM Type 1 message'); }
return { messageType: buffer.readUInt32LE(8), flags: buffer.readUInt32LE(12), domainNameFields: { length: buffer.readUInt16LE(16), maxLength: buffer.readUInt16LE(18), offset: buffer.readUInt32LE(20), }, workstationFields: { length: buffer.readUInt16LE(24), maxLength: buffer.readUInt16LE(26), offset: buffer.readUInt32LE(28), }, }; }
/** * Create NTLM Type 2 challenge message */ private createNTLMType2(challenge: Buffer): Buffer { // Stub implementation - would create proper NTLM Type 2 message const message = Buffer.alloc(48); // NTLM signature Buffer.from('NTLMSSP\0', 'ascii').copy(message, 0); // Message type (2) message.writeUInt32LE(2, 8); // Target name fields (empty) message.writeUInt16LE(0, 12); // Length message.writeUInt16LE(0, 14); // Max length message.writeUInt32LE(48, 16); // Offset // Flags message.writeUInt32LE(0x00020206, 20); // Challenge challenge.copy(message, 24, 0, 8); // Context and target info (empty for now) message.fill(0, 32); return message; }
/** * Parse NTLM Type 3 response message */ private parseNTLMType3(buffer: Buffer): any { // Stub implementation - would parse NTLM Type 3 response if (buffer.length < 52) { throw new Error('Invalid NTLM Type 3 message'); }
return { messageType: buffer.readUInt32LE(8), lmResponse: this.parseNTLMField(buffer, 12), ntlmResponse: this.parseNTLMField(buffer, 20), targetName: this.parseNTLMField(buffer, 28), userName: this.parseNTLMField(buffer, 36), workstationName: this.parseNTLMField(buffer, 44), }; }
/** * Parse NTLM field structure */ private parseNTLMField(buffer: Buffer, offset: number): any { return { length: buffer.readUInt16LE(offset), maxLength: buffer.readUInt16LE(offset + 2), offset: buffer.readUInt32LE(offset + 4), }; }
/** * Validate session setup request */ private validateSessionSetupRequest(request: SMB2SessionSetupRequest): void { if (request.structureSize !== 25) { throw new Error(`Invalid structure size: ${request.structureSize}`); }
if (request.securityBufferLength > 65536) { throw new Error('Security buffer too large'); }
if (request.securityBufferLength > 0 && request.securityBuffer.length !== request.securityBufferLength) { throw new Error('Security buffer length mismatch'); } }
/** * Log session setup details */ private logSessionSetup( request: SMB2SessionSetupRequest, response: SMB2SessionSetupResponse, connection: SMB2Connection, sessionId: bigint, userId: string ): void { this.logger.info('SMB2 Session Setup completed:'); this.logger.info(` Client: ${connection.clientAddress}`); this.logger.info(` Session ID: ${sessionId}`); this.logger.info(` User ID: ${userId}`); this.logger.info(` Session flags: 0x${response.sessionFlags.toString(16)}`); this.logger.info(` Security buffer length: ${response.securityBufferLength}`); }}