readandx and writeandx parsing for smb

remotes/origin/master-1.0.x
Kirby Kuehl 16 years ago committed by Victor Julien
parent 57331ea2a2
commit c20bc68367

@ -96,32 +96,285 @@ void hexdump(const void *buf, size_t len) {
} }
} }
/* For WriteAndX we need to get writeandxdataoffset */ /**
static int SMBParseAndX(void *smb_state, AppLayerParserState *pstate, * \brief SMB Write AndX Request Parsing
*/
static int SMBParseWriteAndX(void *smb_state, AppLayerParserState *pstate,
uint8_t *input, uint32_t input_len, AppLayerParserResult *output) { uint8_t *input, uint32_t input_len, AppLayerParserResult *output) {
SMBState *sstate = (SMBState *) smb_state; SMBState *sstate = (SMBState *) smb_state;
uint8_t *p = input; uint8_t *p = input;
switch (sstate->andx.andxbytesprocessed) { switch (sstate->andx.andxbytesprocessed) {
case 0: case 0:
sstate->andx.paddingparsed = 0;
if (input_len >= 28) {
sstate->andx.andxcommand = *p;
sstate->andx.andxoffset = *(p+2) << 8;
sstate->andx.andxoffset |= *(p+3);
sstate->andx.datalength = *(p+18) << 16;
sstate->andx.datalength |= *(p+19) << 24;
sstate->andx.datalength |= *(p+20) << 8;
sstate->andx.datalength |= *(p+21);
sstate->andx.dataoffset = *(p+22) << 8;
sstate->andx.dataoffset|= *(p+23);
sstate->andx.dataoffset|= (uint64_t) *(p+24) << 56;
sstate->andx.dataoffset|= (uint64_t) *(p+25) << 48;
sstate->andx.dataoffset|= (uint64_t) *(p+26) << 40;
sstate->andx.dataoffset|= (uint64_t) *(p+27) << 32;
input_len -= 28;
sstate->bytesprocessed += 28;
return 28;
} else {
sstate->andx.andxcommand = *(p++); sstate->andx.andxcommand = *(p++);
if (!(--input_len)) break; if (!(--input_len)) break;
case 2: }
case 1:
p++; // Reserved p++; // Reserved
if (!(--input_len)) break; if (!(--input_len)) break;
case 2:
sstate->andx.andxoffset = *(p++) << 8;
if (!(--input_len)) break;
case 3: case 3:
sstate->andx.andxoffset |= *(p++) << 8; sstate->andx.andxoffset |= *(p++);
if (!(--input_len)) break; if (!(--input_len)) break;
case 4: case 4:
sstate->andx.andxoffset |= *(p++); // SMB_COM_WRITE_ANDX Fid 1
p++;
if (!(--input_len)) break;
case 5:
// SMB_COM_WRITE_ANDX Fid 2
p++;
if (!(--input_len)) break;
case 6:
// SMB_COM_WRITE_ANDX Offset 1
p++;
if (!(--input_len)) break;
case 7:
// SMB_COM_WRITE_ANDX Offset 2
p++;
if (!(--input_len)) break;
case 8:
// SMB_COM_WRITE_ANDX Offset 3
p++;
if (!(--input_len)) break;
case 9:
// SMB_COM_WRITE_ANDX Offset 4
p++;
if (!(--input_len)) break;
case 10:
// SMB_COM_WRITE_ANDX Reserved 1
p++;
if (!(--input_len)) break;
case 11:
// SMB_COM_WRITE_ANDX Reserved 2
p++;
if (!(--input_len)) break;
case 12:
// SMB_COM_WRITE_ANDX Reserved 3
p++;
if (!(--input_len)) break;
case 13:
// SMB_COM_WRITE_ANDX Reserved 4
p++;
if (!(--input_len)) break;
case 14:
// SMB_COM_WRITE_ANDX WriteMode 1
p++;
if (!(--input_len)) break;
case 15:
// SMB_COM_WRITE_ANDX WriteMode 2
p++;
if (!(--input_len)) break;
case 16:
// SMB_COM_WRITE_ANDX BytesRemaining 1
p++;
if (!(--input_len)) break;
case 17:
// SMB_COM_WRITE_ANDX BytesRemaining 2
p++;
if (!(--input_len)) break;
case 18:
// DataLengthHigh 1
sstate->andx.datalength = *(p++) << 16;
if (!(--input_len)) break;
case 19:
// DataLengthHigh 2
sstate->andx.datalength |= *(p++) << 24;
if (!(--input_len)) break;
case 20:
// DataLength 1
sstate->andx.datalength |= *(p++) << 8;
if (!(--input_len)) break;
case 21:
// DataLength 2
sstate->andx.datalength |= *(p++);
if (!(--input_len)) break;
case 22:
sstate->andx.dataoffset = *(p++) << 8;
if (!(--input_len)) break;
case 23:
sstate->andx.dataoffset |= *(p++);
if (!(--input_len)) break;
case 24:
sstate->andx.dataoffset|= (uint64_t) *(p++) << 56;
if (!(--input_len)) break;
case 25:
sstate->andx.dataoffset|= (uint64_t) *(p++) << 48;
if (!(--input_len)) break; if (!(--input_len)) break;
case 26:
sstate->andx.dataoffset|= (uint64_t) *(p++) << 40;
if (!(--input_len)) break;
case 27:
sstate->andx.dataoffset|= (uint64_t) *(p++) << 32;
--input_len;
break;
default: default:
// SHOULD NEVER OCCUR
return 0;
}
sstate->bytesprocessed += (p - input);
return (p - input);
}
/**
* \brief SMB Read AndX Response Parsing
*/
static int SMBParseReadAndX(void *smb_state, AppLayerParserState *pstate,
uint8_t *input, uint32_t input_len, AppLayerParserResult *output) {
SMBState *sstate = (SMBState *) smb_state;
uint8_t *p = input;
switch (sstate->andx.andxbytesprocessed) {
case 0:
sstate->andx.paddingparsed = 0;
if (input_len >= 24) {
sstate->andx.andxcommand = *p;
sstate->andx.andxoffset = *(p+2) << 8;
sstate->andx.andxoffset |= *(p+3);
sstate->andx.datalength = *(p+10) << 8;
sstate->andx.datalength |= *(p+11);
sstate->andx.dataoffset = *(p+12) << 8;
sstate->andx.dataoffset |= *(p+13);
sstate->andx.datalength |= (uint64_t) *(p+14) << 56;
sstate->andx.datalength |= (uint64_t) *(p+15) << 48;
sstate->andx.datalength |= (uint64_t) *(p+16) << 40;
sstate->andx.datalength |= (uint64_t) *(p+17) << 32;
input_len -= 24;
sstate->bytesprocessed += 24;
return 24;
} else {
sstate->andx.andxcommand = *(p++);
if (!(--input_len)) break;
}
case 1:
p++; // Reserved
if (!(--input_len)) break;
case 2:
sstate->andx.andxoffset |= *(p++) << 8;
if (!(--input_len)) break;
case 3:
sstate->andx.andxoffset |= *(p++);
if (!(--input_len)) break;
case 4:
// SMB_COM_READ_ANDX Remaining Reserved must be 0xff
p++;
if (!(--input_len)) break;
case 5:
// SMB_COM_READ_ANDX Remaining Reserved must be 0xff
p++;
if (!(--input_len)) break;
case 6:
// SMB_COM_READ_ANDX DataCompactionMode 1
p++;
if (!(--input_len)) break;
case 7:
// SMB_COM_READ_ANDX DataCompactionMode 1
p++;
if (!(--input_len)) break;
case 8:
// SMB_COM_READ_ANDX Reserved
p++;
if (!(--input_len)) break;
case 9:
// SMB_COM_READ_ANDX Reserved
p++;
if (!(--input_len)) break;
case 10:
sstate->andx.datalength = *(p++) << 8;
if (!(--input_len)) break;
case 11:
sstate->andx.datalength |= *(p++);
if (!(--input_len)) break;
case 12:
sstate->andx.dataoffset = *(p++) << 8;
if (!(--input_len)) break;
case 13:
sstate->andx.dataoffset|= *(p++);
if (!(--input_len)) break;
case 14:
sstate->andx.datalength |= *(p++) << 24;
if (!(--input_len)) break;
case 15:
sstate->andx.datalength |= *(p++) << 16;
if (!(--input_len)) break;
case 16:
// SMB_COM_READ_ANDX Reserved
p++;
if (!(--input_len)) break;
case 17:
// SMB_COM_READ_ANDX Reserved
p++;
if (!(--input_len)) break;
case 18:
// SMB_COM_READ_ANDX Reserved
p++;
--input_len;
break; break;
default:
// SHOULD NEVER OCCUR
return 0;
} }
return 0; return 0;
sstate->bytesprocessed += (p - input);
return (p - input);
} }
/* /**
* Obtain SMB WordCount which is 2 times the value. * Handle variable length padding for WriteAndX and ReadAndX
*/
static int PaddingParser(void *smb_state, AppLayerParserState *pstate,
uint8_t *input, uint32_t input_len, AppLayerParserResult *output) {
SMBState *sstate = (SMBState *) smb_state;
uint8_t *p = input;
while (sstate->bytesprocessed++ < sstate->andx.dataoffset && sstate->bytecount.bytecount-- && input_len--) {
p++;
}
if (sstate->bytesprocessed == sstate->andx.dataoffset) {
sstate->andx.paddingparsed = 1;
}
sstate->bytesprocessed += (p - input);
return (p - input);
}
/**
* \brief Parse WriteAndX and ReadAndX Data
* \todo Hand off to DCERPC parser for DCERPC over SMB
*/
static int DataParser(void *smb_state, AppLayerParserState *pstate,
uint8_t *input, uint32_t input_len, AppLayerParserResult *output) {
SMBState *sstate = (SMBState *) smb_state;
uint8_t *p = input;
if (sstate->andx.paddingparsed) {
while (sstate->andx.datalength-- && sstate->bytecount.bytecount-- && input_len--) {
printf("0x%02x ", *(p++));
}
}
sstate->bytesprocessed += (p - input);
return (p - input);
}
/**
* \brief Obtain SMB WordCount which is 2 times the value.
* Reset bytecount.bytecountbytes to 0. * Reset bytecount.bytecountbytes to 0.
* Determine if this is an SMB AndX Command * Determine if this is an SMB AndX Command
*/ */
@ -169,31 +422,68 @@ static int SMBGetByteCount(void *smb_state, AppLayerParserState *pstate,
SCReturnInt(p - input); SCReturnInt(p - input);
} }
/**
* \brief SMBParseWordCount parses the SMB Wordcount portion of the SMB Transaction.
* until sstate->wordcount.wordcount bytes are parsed.
*/
static int SMBParseWordCount(void *smb_state, AppLayerParserState *pstate, static int SMBParseWordCount(void *smb_state, AppLayerParserState *pstate,
uint8_t *input, uint32_t input_len, AppLayerParserResult *output) uint8_t *input, uint32_t input_len, AppLayerParserResult *output)
{ {
SCEnter(); SCEnter();
SMBState *sstate = (SMBState *) smb_state; SMBState *sstate = (SMBState *) smb_state;
uint8_t *p = input; uint8_t *p = input;
while (sstate->wordcount.wordcount > 0 && input_len > 0) { uint32_t retval = 0;
if (sstate->andx.isandx) { uint32_t parsed = 0;
SMBParseAndX(smb_state, pstate, input, input_len, output); if ((sstate->smb.flags & SMB_FLAGS_SERVER_TO_REDIR) && sstate->smb.command == SMB_COM_READ_ANDX) {
} retval = SMBParseReadAndX(sstate, pstate, input + parsed, input_len, output);
SCLogDebug("0x%02x", *(p++)); parsed += retval;
input_len -= retval;
sstate->wordcount.wordcount--; sstate->wordcount.wordcount -= retval;
input_len--; return retval;
} else if (((sstate->smb.flags & SMB_FLAGS_SERVER_TO_REDIR) == 0) && sstate->smb.command == SMB_COM_WRITE_ANDX) {
retval = SMBParseWriteAndX(sstate, pstate, input + parsed, input_len, output);
parsed += retval;
input_len -= retval;
sstate->wordcount.wordcount -= retval;
return retval;
} else { /* Generic WordCount Handler */
while (sstate->wordcount.wordcount-- && input_len--) {
printf("0x%02x ", *(p++));
} }
printf("\n");
sstate->bytesprocessed += (p - input); sstate->bytesprocessed += (p - input);
return (p - input);
SCReturnInt(p - input); SCReturnInt(p - input);
}
} }
/**
* \brief SMBParseByteCount parses the SMB ByteCount portion of the SMB Transaction.
* until sstate->bytecount.bytecount bytes are parsed.
*/
static int SMBParseByteCount(void *smb_state, AppLayerParserState *pstate, static int SMBParseByteCount(void *smb_state, AppLayerParserState *pstate,
uint8_t *input, uint32_t input_len, AppLayerParserResult *output) uint8_t *input, uint32_t input_len, AppLayerParserResult *output)
{ {
SCEnter(); SCEnter();
SMBState *sstate = (SMBState *) smb_state; SMBState *sstate = (SMBState *) smb_state;
uint8_t *p = input; uint8_t *p = input;
uint32_t retval = 0;
uint32_t parsed = 0;
if (((sstate->smb.flags & SMB_FLAGS_SERVER_TO_REDIR) && sstate->smb.command == SMB_COM_READ_ANDX) ||
(((sstate->smb.flags & SMB_FLAGS_SERVER_TO_REDIR) == 0) && sstate->smb.command == SMB_COM_WRITE_ANDX)) {
if (sstate->andx.paddingparsed == 0) {
retval = PaddingParser(sstate, pstate, input + parsed, input_len, output);
parsed += retval;
input_len -= retval;
}
if (sstate->andx.datalength) {
retval = DataParser(sstate, pstate, input + parsed, input_len, output);
parsed += retval;
input_len -= retval;
}
}
while (sstate->bytecount.bytecount && input_len) { while (sstate->bytecount.bytecount && input_len) {
SCLogDebug("0x%02x bytecount %u input_len %u", *(p++), SCLogDebug("0x%02x bytecount %u input_len %u", *(p++),
sstate->bytecount.bytecount, input_len); sstate->bytecount.bytecount, input_len);
@ -486,6 +776,12 @@ static int SMBParse(void *smb_state, AppLayerParserState *pstate,
SCReturnInt(1); SCReturnInt(1);
} }
/**
* \brief determines if the SMB command is an ANDX command
* \retval 1 if smb command is an AndX command
* \retval 0 if smb command is not an AndX command
*/
int isAndX(SMBState *smb_state) { int isAndX(SMBState *smb_state) {
switch (smb_state->smb.command) { switch (smb_state->smb.command) {
case SMB_NO_SECONDARY_ANDX_COMMAND: case SMB_NO_SECONDARY_ANDX_COMMAND:
@ -497,6 +793,7 @@ int isAndX(SMBState *smb_state) {
case SMB_COM_LOGOFF_ANDX: case SMB_COM_LOGOFF_ANDX:
case SMB_COM_TREE_CONNECT_ANDX: case SMB_COM_TREE_CONNECT_ANDX:
case SMB_COM_NT_CREATE_ANDX: case SMB_COM_NT_CREATE_ANDX:
smb_state->andx.andxbytesprocessed = 0;
return 1; return 1;
default: default:
return 0; return 0;
@ -522,25 +819,15 @@ static void SMBStateFree(void *s) {
void RegisterSMBParsers(void) { void RegisterSMBParsers(void) {
AppLayerRegisterProto("smb", ALPROTO_SMB, STREAM_TOSERVER, SMBParse); AppLayerRegisterProto("smb", ALPROTO_SMB, STREAM_TOSERVER, SMBParse);
AppLayerRegisterProto("smb", ALPROTO_SMB, STREAM_TOCLIENT, SMBParse); AppLayerRegisterProto("smb", ALPROTO_SMB, STREAM_TOCLIENT, SMBParse);
/*AppLayerRegisterParser("nbss.hdr", ALPROTO_SMB, SMB_PARSE_NBSS_HEADER,
NBSSParseHeader, "smb");
AppLayerRegisterParser("smb.hdr", ALPROTO_SMB, SMB_PARSE_SMB_HEADER,
SMBParseHeader, "smb");
AppLayerRegisterParser("smb.getwordcount", ALPROTO_SMB, SMB_PARSE_GET_WORDCOUNT,
SMBGetWordCount, "smb");
AppLayerRegisterParser("smb.wordcount", ALPROTO_SMB, SMB_PARSE_WORDCOUNT,
SMBParseWordCount, "smb");
AppLayerRegisterParser("smb.getbytecount", ALPROTO_SMB, SMB_PARSE_GET_BYTECOUNT,
SMBGetByteCount, "smb");
AppLayerRegisterParser("smb.bytecount", ALPROTO_SMB, SMB_PARSE_BYTECOUNT,
SMBParseByteCount, "smb");
*/
AppLayerRegisterStateFuncs(ALPROTO_SMB, SMBStateAlloc, SMBStateFree); AppLayerRegisterStateFuncs(ALPROTO_SMB, SMBStateAlloc, SMBStateFree);
} }
/* UNITTESTS */ /* UNITTESTS */
#ifdef UNITTESTS #ifdef UNITTESTS
/**
* \test SMBParserTest01 tests the NBSS and SMB header decoding
*/
int SMBParserTest01(void) { int SMBParserTest01(void) {
int result = 1; int result = 1;
Flow f; Flow f;

@ -74,10 +74,12 @@ typedef struct bytecount_ {
typedef struct andxcount_ { typedef struct andxcount_ {
uint8_t isandx; uint8_t isandx;
uint8_t paddingparsed;
uint8_t andxcommand; uint8_t andxcommand;
uint16_t andxoffset; uint16_t andxoffset;
uint16_t andxbytesprocessed; uint16_t andxbytesprocessed;
uint64_t writeandxoffset; uint32_t datalength;
uint64_t dataoffset;
}andx_t, *pandx_t; }andx_t, *pandx_t;
typedef struct SMBState_ { typedef struct SMBState_ {

Loading…
Cancel
Save