smb and dcerpc work

remotes/origin/master-1.0.x
Kirby Kuehl 15 years ago committed by Victor Julien
parent bf72331849
commit ecaa701bdf

@ -125,6 +125,8 @@ app-layer-detect-proto.c app-layer-detect-proto.h \
app-layer-parser.c app-layer-parser.h \
app-layer-http.c app-layer-http.h \
app-layer-tls.c app-layer-tls.h \
app-layer-smb.c app-layer-smb.h \
app-layer-dcerpc.c app-layer-dcerpc.h \
app-layer-protos.h \
conf.c conf.h \
conf-yaml-loader.c conf-yaml-loader.h \

@ -0,0 +1,243 @@
/*
* Copyright (c) 2009 Open Information Security Foundation
* app-layer-dcerpc.c
*
* \author Kirby Kuehl <kkuehl@gmail.com>
*/
#include "eidps-common.h"
#include "debug.h"
#include "decode.h"
#include "threads.h"
#include "util-print.h"
#include "util-pool.h"
#include "stream-tcp-private.h"
#include "stream-tcp-reassemble.h"
#include "stream.h"
#include "app-layer-protos.h"
#include "app-layer-parser.h"
#include "util-binsearch.h"
#include "util-unittest.h"
#include "app-layer-dcerpc.h"
enum {
DCERPC_FIELD_NONE = 0,
DCERPC_PARSE_DCERPC_HEADER,
DCERPC_PARSE_DCERPC_BIND,
DCERPC_PARSE_DCERPC_BIND_ACK,
DCERPC_PARSE_DCERPC_REQUEST,
/* must be last */
DCERPC_FIELD_MAX,
};
static int DCERPCParseHeader(void *dcerpc_state, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, AppLayerParserResult *output) {
DCERPCState *sstate = (DCERPCState *)dcerpc_state;
uint8_t *p = input;
// hexdump(p, input_len);
if (input_len) {
switch (sstate->bytesprocessed) {
case 0:
if (input_len >= DCERPC_HDR_LEN + 1) {
if (*p != 5) return 1;
if (!(*(p + 1 ) == 0 || (*(p + 1) == 1))) return 2;
sstate->dcerpc.rpc_vers = *p;
sstate->dcerpc.rpc_vers_minor = *(p + 1);
sstate->dcerpc.type = *(p + 2);
sstate->dcerpc.pfc_flags = *(p + 3);
sstate->dcerpc.packed_drep[0] = *(p + 4);
sstate->dcerpc.packed_drep[1] = *(p + 5);
sstate->dcerpc.packed_drep[2] = *(p + 6);
sstate->dcerpc.packed_drep[3] = *(p + 7);
sstate->dcerpc.frag_length |= *(p + 8) << 8;
sstate->dcerpc.frag_length |= *(p + 9);
sstate->dcerpc.auth_length |= *(p + 10) << 8;
sstate->dcerpc.auth_length |= *(p + 11);
sstate->dcerpc.call_id |= *(p + 12) << 24;
sstate->dcerpc.call_id |= *(p + 13) << 16;
sstate->dcerpc.call_id |= *(p + 14) << 8;
sstate->dcerpc.call_id |= *(p + 15);
return 1;
break;
} else {
sstate->dcerpc.rpc_vers = *(p++);
if (sstate->dcerpc.rpc_vers != 5) return 2;
if (!(--input_len)) break;
}
case 1:
sstate->dcerpc.rpc_vers_minor = *(p++);
if ((sstate->dcerpc.rpc_vers_minor != 0) ||
(sstate->dcerpc.rpc_vers_minor != 1)) return 3;
if (!(--input_len)) break;
case 2:
sstate->dcerpc.type = *(p++);
if (!(--input_len)) break;
case 3:
sstate->dcerpc.pfc_flags = *(p++);
if (!(--input_len)) break;
case 4:
sstate->dcerpc.packed_drep[0] = *(p++);
if (!(--input_len)) break;
case 5:
sstate->dcerpc.packed_drep[1] = *(p++);
if (!(--input_len)) break;
case 6:
sstate->dcerpc.packed_drep[2] = *(p++);
if (!(--input_len)) break;
case 7:
sstate->dcerpc.packed_drep[3] = *(p++);
if (!(--input_len)) break;
case 8:
sstate->dcerpc.frag_length |= *(p++) << 8;
if (!(--input_len)) break;
case 9:
sstate->dcerpc.frag_length |= *(p++);
if (!(--input_len)) break;
case 10:
sstate->dcerpc.auth_length |= *(p++) << 8;
if (!(--input_len)) break;
case 11:
sstate->dcerpc.auth_length |= *(p++);
if (!(--input_len)) break;
case 12:
sstate->dcerpc.call_id |= *(p++) << 24;
if (!(--input_len)) break;
case 13:
sstate->dcerpc.call_id |= *(p++) << 16;
if (!(--input_len)) break;
case 14:
sstate->dcerpc.call_id |= *(p++) << 8;
if (!(--input_len)) break;
case 15:
sstate->dcerpc.call_id |= *(p++);
--input_len;
break;
default: // SHOULD NEVER OCCUR
printf("Odd\n");
return 8;
}
}
sstate->bytesprocessed += (p - input);
return 0;
}
static int DCERPCParse(void *dcerpc_state, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, AppLayerParserResult *output) {
// DCERPCState *sstate = (DCERPCState *)dcerpc_state;
uint16_t max_fields = 3;
uint16_t u = 0;
uint32_t offset = 0;
if (pstate == NULL)
return -1;
for (u = pstate->parse_field; u < max_fields; u++) {
printf("DCERPCParse: u %" PRIu32 "\n", u);
switch(u) {
case 0:
{
int r = AlpParseFieldBySize(output, pstate, DCERPC_PARSE_DCERPC_HEADER, DCERPC_HDR_LEN, input, input_len, &offset);
if (r == 0) {
pstate->parse_field = 0;
return 0;
}
break;
}
}
}
pstate->parse_field = 0;
pstate->flags |= APP_LAYER_PARSER_DONE;
return 1;
}
static void *DCERPCStateAlloc(void) {
void *s = malloc(sizeof(DCERPCState));
if (s == NULL)
return NULL;
memset(s, 0, sizeof(DCERPCState));
return s;
}
static void DCERPCStateFree(void *s) {
if (s) {
free(s);
s = NULL;
}
}
void RegisterDCERPCParsers(void) {
AppLayerRegisterProto("dcerpc", ALPROTO_DCERPC, STREAM_TOSERVER, DCERPCParse);
AppLayerRegisterProto("dcerpc", ALPROTO_DCERPC, STREAM_TOCLIENT, DCERPCParse);
AppLayerRegisterParser("dcerpc.hdr", ALPROTO_DCERPC, DCERPC_PARSE_DCERPC_HEADER, DCERPCParseHeader, "dcerpc");
AppLayerRegisterStateFuncs(ALPROTO_DCERPC, DCERPCStateAlloc, DCERPCStateFree);
}
/* UNITTESTS */
#ifdef UNITTESTS
int DCERPCParserTest01(void) {
int result = 1;
Flow f;
uint8_t dcerpcbuf[] = "\x05\x00\x0b\x03\x10\x00\x00\x00\x48\x00\x00\x00"
"\x00\x00\x00\x00\xd0\x16\xd0\x16\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00"
"\x01\x00\xb8\x4a\x9f\x4d\x1c\x7d\xcf\x11\x86\x1e\x00\x20\xaf\x6e\x7c\x57"
"\x00\x00\x00\x00\x04\x5d\x88\x8a\xeb\x1c\xc9\x11\x9f\xe8\x08\x00\x2b\x10"
"\x48\x60\x02\x00\x00\x00";
uint32_t dcerpclen = sizeof(dcerpcbuf) - 1;
TcpSession ssn;
memset(&f, 0, sizeof(f));
memset(&ssn, 0, sizeof(ssn));
StreamL7DataPtrInit(&ssn,StreamL7GetStorageSize());
f.protoctx = (void *)&ssn;
int r = AppLayerParse(&f, ALPROTO_DCERPC, STREAM_TOSERVER|STREAM_EOF, dcerpcbuf, dcerpclen, FALSE);
if (r != 0) {
printf("dcerpc header check returned %" PRId32 ", expected 0: ", r);
result = 0;
goto end;
}
DCERPCState *dcerpc_state = ssn.aldata[AlpGetStateIdx(ALPROTO_DCERPC)];
if (dcerpc_state == NULL) {
printf("no dcerpc state: ");
result = 0;
goto end;
}
if (dcerpc_state->dcerpc.rpc_vers != 5) {
printf("expected dcerpc version 0x05, got 0x%02x : ",
dcerpc_state->dcerpc.rpc_vers);
result = 0;
goto end;
}
if (dcerpc_state->dcerpc.type != BIND) {
printf("expected dcerpc type 0x%02x , got 0x%02x : ", BIND, dcerpc_state->dcerpc.type);
result = 0;
goto end;
}
end:
return result;
}
void DCERPCParserRegisterTests(void) {
printf("DCERPCParserRegisterTests\n");
UtRegisterTest("DCERPCParserTest01", DCERPCParserTest01, 1);
}
#endif

@ -0,0 +1,122 @@
/*
* Copyright (c) 2009 Open Information Security Foundation
* app-layer-dcerpc.h
*
* \author Kirby Kuehl <kkuehl@gmail.com>
*/
#ifndef APPLAYERDCERPC_H_
#define APPLAYERDCERPC_H_
#include "app-layer-protos.h"
#include "app-layer-parser.h"
#include "flow.h"
void RegisterDCERPCParsers(void);
void DCERPCParserTests(void);
void DCERPCParserRegisterTests(void);
// http://www.opengroup.org/onlinepubs/9629399/chap12.htm#tagcjh_17_06
#define REQUEST 0
#define PING 1
#define RESPONSE 2
#define FAULT 3
#define WORKING 4
#define NOCALL 5
#define REJECT 6
#define ACK 7
#define CL_CANCEL 8
#define FACK 9
#define CANCEL_ACK 10
#define BIND 11
#define BIND_ACK 12
#define BIND_NAK 13
#define ALTER_CONTEXT 14
#define ALTER_CONTEXT_RESP 15
#define SHUTDOWN 17
#define CO_CANCEL 18
#define ORPHANED 19
#if 0
typedef struct {
uint8_t rpc_vers; /* 4 RPC protocol major version (4 LSB only)*/
uint8_t ptype; /* Packet type (5 LSB only) */
uint8_t flags1; /* Packet flags */
uint8_t flags2; /* Packet flags */
uint8_t drep[3]; /* Data representation format label */
uint8_t serial_hi; /* High byte of serial number */
uuid_t object; /* Object identifier */
uuid_t if_id; /* Interface identifier */
uuid_t act_id; /* Activity identifier */
unsigned long server_boot;/* Server boot time */
unsigned long if_vers; /* Interface version */
unsigned long seqnum; /* Sequence number */
unsigned short opnum; /* Operation number */
unsigned short ihint; /* Interface hint */
unsigned short ahint; /* Activity hint */
unsigned short len; /* Length of packet body */
unsigned short fragnum; /* Fragment number */
unsigned small auth_proto; /* Authentication protocol identifier*/
unsigned small serial_lo; /* Low byte of serial number */
} dc_rpc_cl_pkt_hdr_t;
#endif
#define RESERVED_01 0x01
#define LASTFRAG 0x02
#define FRAG 0x04
#define NOFACK 0x08
#define MAYBE 0x10
#define IDEMPOTENT 0x20
#define BROADCAST 0x40
#define RESERVED_80 0x80
#define CANCEL_PENDING 0x02
#define RESERVED_04 0x04
#define RESERVED_10 0x10
#define RESERVED_20 0x20
#define RESERVED_40 0x40
#define RESERVED_80 0x80
typedef struct dcerpc_hdr_ {
uint8_t rpc_vers; /* 00:01 RPC version should be 5 */
uint8_t rpc_vers_minor; /* 01:01 minor version */
uint8_t type; /* 02:01 packet type */
uint8_t pfc_flags; /* 03:01 flags (see PFC_... ) */
uint8_t packed_drep[4]; /* 04:04 NDR data representation format label */
uint16_t frag_length; /* 08:02 total length of fragment */
uint16_t auth_length; /* 10:02 length of auth_value */
uint32_t call_id; /* 12:04 call identifier */
}dcerpc_t;
#define DCERPC_HDR_LEN 16
typedef struct DCERPCState_ {
dcerpc_t dcerpc;
uint16_t bytesprocessed;
}DCERPCState;
#define PFC_FIRST_FRAG 0x01/* First fragment */
#define PFC_LAST_FRAG 0x02/* Last fragment */
#define PFC_PENDING_CANCEL 0x04/* Cancel was pending at sender */
#define PFC_RESERVED_1 0x08
#define PFC_CONC_MPX 0x10/* supports concurrent multiplexing
* of a single connection. */
#define PFC_DID_NOT_EXECUTE 0x20/* only meaningful on `fault' packet;
* if true, guaranteed call did not
* execute. */
#define PFC_MAYBE 0x40/* `maybe' call semantics requested */
#define PFC_OBJECT_UUID 0x80/* if true, a non-nil object UUID
* was specified in the handle, and
* is present in the optional object
* field. If false, the object field
* is omitted. */
#define REASON_NOT_SPECIFIED 0
#define TEMPORARY_CONGESTION 1
#define LOCAL_LIMIT_EXCEEDED 2
#define CALLED_PADDR_UNKNOWN 3 /* not used */
#define PROTOCOL_VERSION_NOT_SUPPORTED 4
#define DEFAULT_CONTEXT_NOT_SUPPORTED 5 /* not used */
#define USER_DATA_NOT_READABLE 6 /* not used */
#define NO_PSAP_AVAILABLE 7 /* not used */
#endif /* APPLAYERDCERPC_H_ */

@ -202,6 +202,14 @@ void AppLayerDetectProtoThreadInit(void) {
AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_JABBER, "xmlns='jabber|3A|client'", 74, 53, STREAM_TOCLIENT);
AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_JABBER, "xmlns='jabber|3A|client'", 74, 53, STREAM_TOSERVER);
/** SMB */
AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_SMB, "|ff 53 4d 42|", 4, 4, STREAM_TOCLIENT);
AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_SMB, "|ff 53 4d 42|", 4, 4, STREAM_TOSERVER);
/** DCERPC */
AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_DCERPC, "|05 00|", 2, 0, STREAM_TOCLIENT);
AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_DCERPC, "|05 00|", 2, 0, STREAM_TOSERVER);
AlpProtoFinalizeGlobal(&alp_proto_ctx);
AlpProtoFinalizeThread(&alp_proto_ctx, &alp_proto_tctx);
}

@ -12,6 +12,8 @@ enum {
ALPROTO_IMAP,
ALPROTO_MSN,
ALPROTO_JABBER,
ALPROTO_SMB,
ALPROTO_DCERPC,
/* keep last */
ALPROTO_MAX,

@ -0,0 +1,597 @@
/*
* Copyright (c) 2009 Open Information Security Foundation
* app-layer-smb.c
*
* \author Kirby Kuehl <kkuehl@gmail.com>
*/
#include "eidps-common.h"
#include "debug.h"
#include "decode.h"
#include "threads.h"
#include "util-print.h"
#include "util-pool.h"
#include "stream-tcp-private.h"
#include "stream-tcp-reassemble.h"
#include "stream.h"
#include "app-layer-protos.h"
#include "app-layer-parser.h"
#include "util-binsearch.h"
#include "util-unittest.h"
#include "app-layer-smb.h"
enum {
SMB_FIELD_NONE = 0,
SMB_PARSE_NBSS_HEADER,
SMB_PARSE_SMB_HEADER,
SMB_PARSE_GET_WORDCOUNT,
SMB_PARSE_WORDCOUNT,
SMB_PARSE_GET_BYTECOUNT,
SMB_PARSE_BYTECOUNT,
/* must be last */
SMB_FIELD_MAX,
};
void hexdump(const void *buf, size_t len) {
/* dumps len bytes of *buf to stdout. Looks like:
* [0000] 75 6E 6B 6E 6F 77 6E 20
* 30 FF 00 00 00 00 39 00 unknown 0.....9.
* (in a single line of course)
*/
const unsigned char *p = buf;
unsigned char c;
size_t n;
char bytestr[4] = { 0 };
char addrstr[10] = { 0 };
char hexstr[16 * 3 + 5] = { 0 };
char charstr[16 * 1 + 5] = { 0 };
for (n = 1; n <= len; n++) {
if (n % 16 == 1) {
/* store address for this line */
#if __WORDSIZE == 64
snprintf(addrstr, sizeof(addrstr), "%.4lx",
((uint64_t)p-(uint64_t)buf) );
#else
snprintf(addrstr, sizeof(addrstr), "%.4x", ((uint32_t) p
- (uint32_t) buf));
#endif
}
c = *p;
if (isalnum(c) == 0) {
c = '.';
}
/* store hex str (for left side) */
snprintf(bytestr, sizeof(bytestr), "%02X ", *p);
strncat(hexstr, bytestr, sizeof(hexstr) - strlen(hexstr) - 1);
/* store char str (for right side) */
snprintf(bytestr, sizeof(bytestr), "%c", c);
strncat(charstr, bytestr, sizeof(charstr) - strlen(charstr) - 1);
if (n % 16 == 0) {
/* line completed */
printf("[%4.4s] %-50.50s %s\n", addrstr, hexstr, charstr);
hexstr[0] = 0;
charstr[0] = 0;
} else if (n % 8 == 0) {
/* half line: add whitespaces */
strncat(hexstr, " ", sizeof(hexstr) - strlen(hexstr) - 1);
strncat(charstr, " ", sizeof(charstr) - strlen(charstr) - 1);
}
p++; /* next byte */
}
if (strlen(hexstr) > 0) {
/* print rest of buffer if not empty */
printf("[%4.4s] %-50.50s %s\n", addrstr, hexstr, charstr);
}
}
static int SMBParseAndX(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.andxcommand = *(p++);
if (!(--input_len)) break;
case 2:
p++; // Reserved
if (!(--input_len)) break;
case 3:
sstate->andx.andxoffset |= *(p++) << 8;
if (!(--input_len)) break;
case 4:
sstate->andx.andxoffset |= *(p++);
if (!(--input_len)) break;
default:
break;
}
return 0;
}
/*
* Obtain SMB WordCount which is 2 times the value.
* Reset bytecount.bytecountbytes to 0.
* Determine if this is an SMB AndX Command
*/
static int SMBGetWordCount(void *smb_state, AppLayerParserState *pstate,
uint8_t *input, uint32_t input_len, AppLayerParserResult *output) {
if (input_len) {
SMBState *sstate = (SMBState *) smb_state;
sstate->wordcount.wordcount = *(input) * 2;
sstate->bytesprocessed++;
sstate->bytecount.bytecountbytes = 0;
sstate->andx.isandx = isAndX(sstate);
printf("Wordcount (%u):\n", sstate->wordcount.wordcount);
return 1;
}
return 0;
}
/*
* Obtain SMB Bytecount. Handle the corner obfuscation case where a packet boundary
* is after the first bytecount byte.
*/
static int SMBGetByteCount(void *smb_state, AppLayerParserState *pstate,
uint8_t *input, uint32_t input_len, AppLayerParserResult *output) {
if (input_len) {
SMBState *sstate = (SMBState *) smb_state;
uint8_t *p = input;
switch(sstate->bytecount.bytecountbytes) {
case 0:
sstate->bytecount.bytecount = *(p++) << 8;
sstate->bytecount.bytecountbytes++;
if (!(--input_len)) break;
case 1:
sstate->bytecount.bytecount |= *(p++);
sstate->bytecount.bytecountbytes++;
printf("Bytecount %u\n", sstate->bytecount.bytecount);
break;
default:
return 0;
}
sstate->bytesprocessed += (p - input);
return 1;
}
return 0;
}
static int SMBParseWordCount(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->wordcount.wordcount-- && input_len--) {
if (sstate->andx.isandx) {
SMBParseAndX(smb_state, pstate, input, input_len, output);
}
printf("0x%02x\n", *(p++));
}
sstate->bytesprocessed += (p - input);
return 0;
}
static int SMBParseByteCount(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->bytecount.bytecount-- && input_len--) {
printf("0x%02x\n", *(p++));
}
sstate->bytesprocessed += (p - input);
return 0;
}
#define DEBUG 1
static int NBSSParseHeader(void *smb_state, AppLayerParserState *pstate,
uint8_t *input, uint32_t input_len, AppLayerParserResult *output) {
SMBState *sstate = (SMBState *) smb_state;
uint8_t *p = input;
if (input_len && sstate->bytesprocessed < NBSS_HDR_LEN - 1) {
switch (sstate->bytesprocessed) {
case 0:
if (input_len >= NBSS_HDR_LEN) {
sstate->nbss.type = *p;
sstate->nbss.length = (*(p + 1) & 0x01) << 16;
sstate->nbss.length |= *(p + 2) << 8;
sstate->nbss.length |= *(p + 3);
input_len -= NBSS_HDR_LEN;
sstate->bytesprocessed += NBSS_HDR_LEN;
return 0;
} else {
sstate->nbss.type = *(p++);
if (!(--input_len)) break;
}
case 1:
sstate->nbss.length = (*(p++) & 0x01) << 16;
if (!(--input_len)) break;
case 2:
sstate->nbss.length |= *(p++) << 8;
if (!(--input_len)) break;
case 3:
sstate->nbss.length |= *(p++);
--input_len;
break;
default:
return -1;
break;
}
sstate->bytesprocessed += (p - input);
}
return 0;
}
static int SMBParseHeader(void *smb_state, AppLayerParserState *pstate,
uint8_t *input, uint32_t input_len, AppLayerParserResult *output) {
SMBState *sstate = (SMBState *) smb_state;
uint8_t *p = input;
hexdump(p, input_len);
if (input_len) {
switch (sstate->bytesprocessed) {
case 4:
if (input_len >= SMB_HDR_LEN) {
//if (sstate->nbss.type != NBSS_SESSION_MESSAGE) return 1;
//if (sstate->nbss.length < MINIMUM_SMB_LEN) return 2;
if (memcmp(p, "\xff\x53\x4d\x42", 4) != 0) {
printf("SMB Header did not validate\n");
return 3;
}
sstate->smb.command = *(p + 4);
sstate->smb.status = *(p + 5) << 24;
sstate->smb.status |= *(p + 6) << 16;
sstate->smb.status |= *(p + 7) << 8;
sstate->smb.status |= *(p + 8);
sstate->smb.flags = *(p + 9);
sstate->smb.flags2 = *(p + 10) << 8;
sstate->smb.flags2 |= *(p + 11);
sstate->smb.pidhigh = *(p + 12) << 8;
sstate->smb.pidhigh |= *(p + 13);
sstate->smb.securitysignature = (uint64_t) *(p + 14) << 56;
sstate->smb.securitysignature |= (uint64_t) *(p + 15) << 48;
sstate->smb.securitysignature |= (uint64_t) *(p + 16) << 40;
sstate->smb.securitysignature |= (uint64_t) *(p + 17) << 32;
sstate->smb.securitysignature |= (uint64_t) *(p + 18) << 24;
sstate->smb.securitysignature |= (uint64_t) *(p + 19) << 16;
sstate->smb.securitysignature |= (uint64_t) *(p + 20) << 8;
sstate->smb.securitysignature |= (uint64_t) *(p + 21);
sstate->smb.tid = *(p + 24) << 8;
sstate->smb.tid |= *(p + 25);
sstate->smb.pid = *(p + 26) << 8;
sstate->smb.pid |= *(p + 27);
sstate->smb.uid = *(p + 28) << 8;
sstate->smb.uid |= *(p + 29);
sstate->smb.mid = *(p + 30) << 8;
sstate->smb.mid |= *(p + 31);
input_len -= (SMB_HDR_LEN + 1);
sstate->bytesprocessed += (SMB_HDR_LEN + 1);
return 1;
break;
} else {
//sstate->smb.protocol[0] = *(p++);
if (*(p++) != 0xff)
return 4;
if (!(--input_len)) break;
}
case 5:
//sstate->smb.protocol[1] = *(p++);
if (*(p++) != 'S')
return 5;
if (!(--input_len)) break;
case 6:
//sstate->smb.protocol[2] = *(p++);
if (*(p++) != 'M')
return 6;
if (!(--input_len)) break;
case 7:
//sstate->smb.protocol[3] = *(p++);
if (*(p++) != 'B')
return 7;
if (!(--input_len)) break;
case 8:
sstate->smb.command = *(p++);
if (!(--input_len)) break;
case 9:
sstate->smb.status = *(p++) << 24;
if (!(--input_len)) break;
case 10:
sstate->smb.status |= *(p++) << 16;
if (!(--input_len)) break;
case 11:
sstate->smb.status |= *(p++) << 8;
if (!(--input_len)) break;
case 12:
sstate->smb.status |= *(p++);
if (!(--input_len)) break;
case 13:
sstate->smb.flags = *(p++);
if (!(--input_len)) break;
case 14:
sstate->smb.flags2 = *(p++) << 8;
if (!(--input_len)) break;
case 15:
sstate->smb.flags2 |= *(p++);
if (!(--input_len)) break;
case 16:
sstate->smb.pidhigh = *(p++) << 8;
if (!(--input_len)) break;
case 17:
sstate->smb.pidhigh |= *(p++);
if (!(--input_len)) break;
case 18:
sstate->smb.securitysignature = (uint64_t) *(p++) << 56;
if (!(--input_len)) break;
case 19:
sstate->smb.securitysignature |= (uint64_t) *(p++) << 48;
if (!(--input_len)) break;
case 20:
sstate->smb.securitysignature |= (uint64_t) *(p++) << 40;
if (!(--input_len)) break;
case 21:
sstate->smb.securitysignature |= (uint64_t) *(p++) << 32;
if (!(--input_len)) break;
case 22:
sstate->smb.securitysignature |= (uint64_t) *(p++) << 24;
if (!(--input_len)) break;
case 23:
sstate->smb.securitysignature |=(uint64_t) *(p++) << 16;
if (!(--input_len)) break;
case 24:
sstate->smb.securitysignature |= (uint64_t) *(p++) << 8;
if (!(--input_len)) break;
case 25:
sstate->smb.securitysignature |= (uint64_t) *(p++);
if (!(--input_len)) break;
case 26:
p++; // UNUSED
if (!(--input_len)) break;
case 27:
p++; // UNUSED
if (!(--input_len)) break;
case 28:
sstate->smb.tid = *(p++) << 8;
if (!(--input_len)) break;
case 29:
sstate->smb.tid |= *(p++);
if (!(--input_len)) break;
case 30:
sstate->smb.pid = *(p++) << 8;
if (!(--input_len)) break;
case 31:
sstate->smb.pid |= *(p++);
if (!(--input_len)) break;
case 32:
sstate->smb.uid = *(p++) << 8;
if (!(--input_len)) break;
case 33:
sstate->smb.uid |= *(p++);
if (!(--input_len)) break;
case 34:
sstate->smb.mid = *(p++) << 8;
if (!(--input_len)) break;
case 35:
sstate->smb.mid |= *(p++);
--input_len;
break;
default: // SHOULD NEVER OCCUR
return 8;
}
}
sstate->bytesprocessed += (p - input);
return 0;
}
static int SMBParse(void *smb_state, AppLayerParserState *pstate,
uint8_t *input, uint32_t input_len, AppLayerParserResult *output) {
SMBState *sstate = (SMBState *) smb_state;
uint16_t max_fields = 3;
uint16_t u = 0;
uint32_t offset = 0;
if (pstate == NULL)
return -1;
for (u = pstate->parse_field; u < max_fields; u++) {
printf("SMBParse: u %" PRIu32 "\n", u);
switch (u) {
case 0: {
int r = AlpParseFieldBySize(output, pstate, SMB_PARSE_NBSS_HEADER,
NBSS_HDR_LEN, input, input_len, &offset);
if (r == 0) {
pstate->parse_field = 0;
return 0;
}
break;
}
case 1: {
uint8_t *data = input + offset;
uint32_t data_len = input_len - offset;
if (sstate->nbss.type == NBSS_SESSION_MESSAGE) {
int r = AlpParseFieldBySize(output, pstate, SMB_PARSE_SMB_HEADER,
SMB_HDR_LEN, data, data_len, &offset);
if (r == 0) {
pstate->parse_field = 1;
return 0;
}
}
break;
}
case 2: {
uint8_t *data = input + offset;
uint32_t data_len = input_len - offset;
int r = AlpParseFieldBySize(output, pstate, SMB_PARSE_GET_WORDCOUNT,
1, data, data_len, &offset);
if (r == 0) {
pstate->parse_field = 2;
return 0;
}
break;
}
case 3: {
uint8_t *data = input + offset;
uint32_t data_len = input_len - offset;
printf("wordcount %d\n", sstate->wordcount.wordcount);
int r = AlpParseFieldBySize(output, pstate, SMB_PARSE_WORDCOUNT,
sstate->wordcount.wordcount, data, data_len, &offset);
if (r == 0) {
pstate->parse_field = 3;
return 0;
}
break;
}
case 4: {
uint8_t *data = input + offset;
uint32_t data_len = input_len - offset;
int r = AlpParseFieldBySize(output, pstate, SMB_PARSE_GET_BYTECOUNT,
2, data, data_len, &offset);
if (r == 0) {
pstate->parse_field = 4;
return 0;
}
break;
}
case 5: {
uint8_t *data = input + offset;
uint32_t data_len = input_len - offset;
int r = AlpParseFieldBySize(output, pstate, SMB_PARSE_BYTECOUNT,
sstate->bytecount.bytecount, data, data_len, &offset);
if (r == 0) {
pstate->parse_field = 5;
return 0;
}
break;
}
}
}
pstate->parse_field = 0;
pstate->flags |= APP_LAYER_PARSER_DONE;
return 1;
}
int isAndX(SMBState *smb_state) {
switch (smb_state->smb.command) {
case SMB_NO_SECONDARY_ANDX_COMMAND:
case SMB_COM_LOCKING_ANDX:
case SMB_COM_OPEN_ANDX:
case SMB_COM_READ_ANDX:
case SMB_COM_WRITE_ANDX:
case SMB_COM_SESSION_SETUP_ANDX:
case SMB_COM_LOGOFF_ANDX:
case SMB_COM_TREE_CONNECT_ANDX:
case SMB_COM_NT_CREATE_ANDX:
return 1;
default:
return 0;
}
}
static void *SMBStateAlloc(void) {
void *s = malloc(sizeof(SMBState));
if (s == NULL)
return NULL;
memset(s, 0, sizeof(SMBState));
return s;
}
static void SMBStateFree(void *s) {
if (s) {
free(s);
s = NULL;
}
}
void RegisterSMBParsers(void) {
AppLayerRegisterProto("smb", ALPROTO_SMB, STREAM_TOSERVER, 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);
}
/* UNITTESTS */
#ifdef UNITTESTS
int SMBParserTest01(void) {
int result = 1;
Flow f;
uint8_t smbbuf[] = "\x00\x00\x00\x85\xff\x53\x4d\x42\x72\x00\x00\x00\x00"
"\x18\x53\xc8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xfe\x00\x00\x00\x00"
"\x00\x62\x00\x02\x50\x43\x20\x4e\x45\x54\x57\x4f\x52\x4b\x20\x50\x52\x4f\x47\x52\x41\x4d\x20"
"\x31\x2e\x30\x00\x02\x4c\x41\x4e\x4d\x41\x4e\x31\x2e\x30\x00\x02\x57\x69\x6e\x64\x6f\x77\x73"
"\x20\x66\x6f\x72\x20\x57\x6f\x72\x6b\x67\x72\x6f\x75\x70\x73\x20\x33\x2e\x31\x61\x00\x02\x4c"
"\x4d\x31\x2e\x32\x58\x30\x30\x32\x00\x02\x4c\x41\x4e\x4d\x41\x4e\x32\x2e\x31\x00\x02\x4e\x54"
"\x20\x4c\x4d\x20\x30\x2e\x31\x32\x00";
uint32_t smblen = sizeof(smbbuf) - 1;
TcpSession ssn;
memset(&f, 0, sizeof(f));
memset(&ssn, 0, sizeof(ssn));
StreamL7DataPtrInit(&ssn,StreamL7GetStorageSize());
f.protoctx = (void *)&ssn;
int r = AppLayerParse(&f, ALPROTO_SMB, STREAM_TOSERVER|STREAM_EOF, smbbuf, smblen, FALSE);
if (r != 0) {
printf("smb header check returned %" PRId32 ", expected 0: ", r);
result = 0;
goto end;
}
SMBState *smb_state = ssn.aldata[AlpGetStateIdx(ALPROTO_SMB)];
if (smb_state == NULL) {
printf("no smb state: ");
result = 0;
goto end;
}
if (smb_state->nbss.type != NBSS_SESSION_MESSAGE) {
printf("expected nbss type 0x%02x , got 0x%02x : ", NBSS_SESSION_MESSAGE, smb_state->nbss.type);
result = 0;
goto end;
}
if (smb_state->nbss.length != 133) {
printf("expected nbss length 0x%02x , got 0x%02x : ", 133, smb_state->nbss.length);
result = 0;
goto end;
}
if (smb_state->smb.command != SMB_COM_NEGOTIATE) {
printf("expected SMB command 0x%02x , got 0x%02x : ", SMB_COM_NEGOTIATE, smb_state->smb.command);
result = 0;
goto end;
}
end:
return result;
}
void SMBParserRegisterTests(void) {
printf("SMBParserRegisterTests\n");
UtRegisterTest("SMBParserTest01", SMBParserTest01, 1);
}
#endif

@ -0,0 +1,166 @@
/*
* Copyright (c) 2009 Open Information Security Foundation
* app-layer-smb.h
*
* \author Kirby Kuehl <kkuehl@gmail.com>
*/
#ifndef APPLAYERSMB_H_
#define APPLAYERSMB_H_
#include "app-layer-protos.h"
#include "app-layer-parser.h"
#include "flow.h"
#include "stream.h"
#include <stdint.h>
/*
http://ubiqx.org/cifs/rfc-draft/rfc1002.html#s4.3
All session packets are of the following general structure:
1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| TYPE | FLAGS | LENGTH |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
/ TRAILER (Packet Type Dependent) /
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The TYPE, FLAGS, and LENGTH fields are present in every session
packet.
*/
#define NBSS_SESSION_MESSAGE 0x00
#define NBSS_SESSION_REQUEST 0x81
#define NBSS_POSITIVE_SESSION_RESPONSE 0x82
#define NBSS_NEGATIVE_SESSION_RESPONSE 0x83
#define NBSS_RETARGET_SESSION_RESPONSE 0x84
#define NBSS_SESSION_KEEP_ALIVE 0x85
typedef struct nbss_hdr_ {
uint8_t type;
uint8_t flags;
uint32_t length;
}nbss_hdr_t, *pnbss_hdr_t;
#define NBSS_HDR_LEN 4
typedef struct smb_hdr_ {
uint8_t protocol[4];
uint8_t command;
uint32_t status;
uint8_t flags;
uint16_t flags2;
uint16_t pidhigh;
uint64_t securitysignature;
uint16_t unused;
uint16_t tid;
uint16_t pid;
uint16_t uid;
uint16_t mid;
}smb_hdr_t, *psmb_hdr_t;
#define SMB_HDR_LEN 32
#define MINIMUM_SMB_LEN 35
#define NBSS_SMB_HDRS_LEN 36
typedef struct wordcount_ {
uint8_t wordcount;
uint8_t *words;
}wordcount_t, *pwordcount_t;
typedef struct bytecount_ {
uint8_t bytecountbytes;
uint16_t bytecount;
uint8_t *bytes;
}bytecount_t, *pbytyecount_t;
typedef struct andxcount_ {
uint8_t isandx;
uint8_t andxcommand;
uint16_t andxoffset;
uint16_t andxbytesprocessed;
}andx_t, *pandx_t;
typedef struct SMBState_ {
nbss_hdr_t nbss;
smb_hdr_t smb;
wordcount_t wordcount;
bytecount_t bytecount;
andx_t andx;
uint16_t bytesprocessed;
}SMBState;
#define SMB_FLAGS_SERVER_TO_REDIR 0x80
#define SMB_NO_SECONDARY_ANDX_COMMAND 0xff
/* http://msdn.microsoft.com/en-us/library/dd327674.aspx */
#define SMB_COM_CREATE_DIRECTORY 0x00
#define SMB_COM_DELETE_DIRECTORY 0x01
#define SMB_COM_OPEN 0x02
#define SMB_COM_CREATE 0x03
#define SMB_COM_CLOSE 0x04
#define SMB_COM_FLUSH 0x05
#define SMB_COM_DELETE 0x06
#define SMB_COM_RENAME 0x07
#define SMB_COM_QUERY_INFORMATION 0x08
#define SMB_COM_SET_INFORMATION 0x09
#define SMB_COM_READ 0x0A
#define SMB_COM_WRITE 0x0B
#define SMB_COM_LOCK_BYTE_RANGE 0x0C
#define SMB_COM_UNLOCK_BYTE_RANGE 0x0D
#define SMB_COM_CREATE_TEMPORARY 0x0E
#define SMB_COM_CREATE_NEW 0x0F
#define SMB_COM_CHECK_DIRECTORY 0x10
#define SMB_COM_PROCESS_EXIT 0x11
#define SMB_COM_SEEK 0x12
#define SMB_COM_LOCK_AND_READ 0x13
#define SMB_COM_WRITE_AND_UNLOCK 0x14
#define SMB_COM_READ_RAW 0x1A
#define SMB_COM_READ_MPX 0x1B
#define SMB_COM_READ_MPX_SECONDARY 0x1C
#define SMB_COM_WRITE_RAW 0x1D
#define SMB_COM_WRITE_MPX 0x1E
#define SMB_COM_WRITE_COMPLETE 0x20
#define SMB_COM_SET_INFORMATION2 0x22
#define SMB_COM_QUERY_INFORMATION2 0x23
#define SMB_COM_LOCKING_ANDX 0x24
#define SMB_COM_TRANSACTION 0x25
#define SMB_COM_TRANSACTION_SECONDARY 0x26
#define SMB_COM_IOCTL 0x27
#define SMB_COM_IOCTL_SECONDARY 0x28
#define SMB_COM_COPY 0x29
#define SMB_COM_MOVE 0x2A
#define SMB_COM_ECHO 0x2B
#define SMB_COM_WRITE_AND_CLOSE 0x2C
#define SMB_COM_OPEN_ANDX 0x2D
#define SMB_COM_READ_ANDX 0x2E
#define SMB_COM_WRITE_ANDX 0x2F
#define SMB_COM_CLOSE_AND_TREE_DISC 0x31
#define SMB_COM_TRANSACTION2 0x32
#define SMB_COM_TRANSACTION2_SECONDARY 0x33
#define SMB_COM_FIND_CLOSE2 0x34
#define SMB_COM_FIND_NOTIFY_CLOSE 0x35
#define SMB_COM_TREE_CONNECT 0x70
#define SMB_COM_TREE_DISCONNECT 0x71
#define SMB_COM_NEGOTIATE 0x72
#define SMB_COM_SESSION_SETUP_ANDX 0x73
#define SMB_COM_LOGOFF_ANDX 0x74
#define SMB_COM_TREE_CONNECT_ANDX 0x75
#define SMB_COM_QUERY_INFORMATION_DISK 0x80
#define SMB_COM_SEARCH 0x81
#define SMB_COM_FIND 0x82
#define SMB_COM_FIND_UNIQUE 0x83
#define SMB_COM_NT_TRANSACT 0xA0
#define SMB_COM_NT_TRANSACT_SECONDARY 0xA1
#define SMB_COM_NT_CREATE_ANDX 0xA2
#define SMB_COM_NT_CANCEL 0xA4
#define SMB_COM_NT_RENAME 0xA5
#define SMB_COM_OPEN_PRINT_FILE 0xC0
#define SMB_COM_WRITE_PRINT_FILE 0xC1
#define SMB_COM_CLOSE_PRINT_FILE 0xC2
#define SMB_COM_GET_PRINT_QUEUE 0xC3
void RegisterSMBParsers(void);
void SMBParserRegisterTests(void);
int isAndX(SMBState *smb_state);
#endif /* APPLAYERSMB_H_ */

@ -60,6 +60,8 @@
#include "app-layer-parser.h"
#include "app-layer-http.h"
#include "app-layer-tls.h"
#include "app-layer-smb.h"
#include "app-layer-dcerpc.h"
#include "util-radix-tree.h"
#include "util-cidr.h"
@ -396,6 +398,8 @@ int main(int argc, char **argv)
RegisterAppLayerParsers();
RegisterHTTPParsers();
RegisterTLSParsers();
RegisterSMBParsers();
RegisterDCERPCParsers();
AppLayerParsersInitPostProcess();
TmModuleReceiveNFQRegister();
@ -444,6 +448,8 @@ int main(int argc, char **argv)
DecodePPPRegisterTests();
HTTPParserRegisterTests();
TLSParserRegisterTests();
SMBParserRegisterTests();
DCERPCParserRegisterTests();
DecodePPPOERegisterTests();
DecodeICMPV4RegisterTests();
DecodeICMPV6RegisterTests();

Loading…
Cancel
Save