mirror of https://github.com/OISF/suricata
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
223 lines
8.8 KiB
C
223 lines
8.8 KiB
C
/* Copyright (C) 2017-2021 Open Information Security Foundation
|
|
*
|
|
* You can copy, redistribute or modify this Program under the terms of
|
|
* the GNU General Public License version 2 as published by the Free
|
|
* Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* version 2 along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
* 02110-1301, USA.
|
|
*/
|
|
|
|
/**
|
|
* \file
|
|
*
|
|
* SMB protocol handling
|
|
*/
|
|
|
|
#include "suricata-common.h"
|
|
#include "suricata.h"
|
|
|
|
#include "app-layer-protos.h"
|
|
#include "app-layer-detect-proto.h"
|
|
#include "app-layer-parser.h"
|
|
|
|
#include "util-unittest.h"
|
|
|
|
#include "rust.h"
|
|
#include "app-layer-smb.h"
|
|
#include "util-misc.h"
|
|
|
|
|
|
static StreamingBufferConfig sbcfg = STREAMING_BUFFER_CONFIG_INITIALIZER;
|
|
static SuricataFileContext sfc = { &sbcfg };
|
|
|
|
#ifdef UNITTESTS
|
|
static void SMBParserRegisterTests(void);
|
|
#endif
|
|
|
|
void RegisterSMBParsers(void)
|
|
{
|
|
rs_smb_init(&sfc);
|
|
rs_smb_register_parser();
|
|
|
|
#ifdef UNITTESTS
|
|
AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_SMB, SMBParserRegisterTests);
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
#ifdef UNITTESTS
|
|
#include "stream-tcp.h"
|
|
#include "util-unittest-helper.h"
|
|
|
|
/** \test multi transactions and cleanup */
|
|
static int SMBParserTxCleanupTest(void)
|
|
{
|
|
uint64_t ret[4];
|
|
AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
|
|
FAIL_IF_NULL(alp_tctx);
|
|
|
|
StreamTcpInitConfig(true);
|
|
TcpSession ssn;
|
|
memset(&ssn, 0, sizeof(ssn));
|
|
|
|
Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 445);
|
|
FAIL_IF_NULL(f);
|
|
f->protoctx = &ssn;
|
|
f->proto = IPPROTO_TCP;
|
|
f->alproto = ALPROTO_SMB;
|
|
|
|
char req_str[] ="\x00\x00\x00\x79\xfe\x53\x4d\x42\x40\x00\x01\x00\x00\x00\x00\x00" \
|
|
"\x05\x00\xe0\x1e\x10\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00" \
|
|
"\x00\x00\x00\x00\x00\x00\x00\x00\x10\x72\xd2\x9f\x36\xc2\x08\x14" \
|
|
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
|
|
"\x00\x00\x00\x00\x39\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00" \
|
|
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00" \
|
|
"\x00\x00\x00\x00\x07\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00" \
|
|
"\x78\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
|
|
req_str[28] = 0x01;
|
|
int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_SMB,
|
|
STREAM_TOSERVER | STREAM_START, (uint8_t *)req_str, sizeof(req_str));
|
|
FAIL_IF_NOT(r == 0);
|
|
req_str[28]++;
|
|
r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_SMB,
|
|
STREAM_TOSERVER, (uint8_t *)req_str, sizeof(req_str));
|
|
FAIL_IF_NOT(r == 0);
|
|
req_str[28]++;
|
|
r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_SMB,
|
|
STREAM_TOSERVER, (uint8_t *)req_str, sizeof(req_str));
|
|
FAIL_IF_NOT(r == 0);
|
|
req_str[28]++;
|
|
r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_SMB,
|
|
STREAM_TOSERVER, (uint8_t *)req_str, sizeof(req_str));
|
|
FAIL_IF_NOT(r == 0);
|
|
req_str[28]++;
|
|
r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_SMB,
|
|
STREAM_TOSERVER, (uint8_t *)req_str, sizeof(req_str));
|
|
FAIL_IF_NOT(r == 0);
|
|
req_str[28]++;
|
|
r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_SMB,
|
|
STREAM_TOSERVER, (uint8_t *)req_str, sizeof(req_str));
|
|
FAIL_IF_NOT(r == 0);
|
|
req_str[28]++;
|
|
r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_SMB,
|
|
STREAM_TOSERVER, (uint8_t *)req_str, sizeof(req_str));
|
|
FAIL_IF_NOT(r == 0);
|
|
req_str[28]++;
|
|
r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_SMB,
|
|
STREAM_TOSERVER, (uint8_t *)req_str, sizeof(req_str));
|
|
FAIL_IF_NOT(r == 0);
|
|
req_str[28]++;
|
|
|
|
AppLayerParserTransactionsCleanup(f, STREAM_TOSERVER);
|
|
UTHAppLayerParserStateGetIds(f->alparser, &ret[0], &ret[1], &ret[2], &ret[3]);
|
|
FAIL_IF_NOT(ret[0] == 0); // inspect_id[0]
|
|
FAIL_IF_NOT(ret[1] == 0); // inspect_id[1]
|
|
FAIL_IF_NOT(ret[2] == 0); // log_id
|
|
FAIL_IF_NOT(ret[3] == 0); // min_id
|
|
|
|
char resp_str[] = "\x00\x00\x00\x98\xfe\x53\x4d\x42\x40\x00\x01\x00\x00\x00\x00\x00" \
|
|
"\x05\x00\x21\x00\x11\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00" \
|
|
"\x00\x00\x00\x00\x00\x00\x00\x00\x10\x72\xd2\x9f\x36\xc2\x08\x14" \
|
|
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
|
|
"\x00\x00\x00\x00\x59\x00\x00\x00\x01\x00\x00\x00\x48\x38\x40\xb3" \
|
|
"\x0f\xa8\xd3\x01\x84\x9a\x2b\x46\xf7\xa8\xd3\x01\x48\x38\x40\xb3" \
|
|
"\x0f\xa8\xd3\x01\x48\x38\x40\xb3\x0f\xa8\xd3\x01\x00\x00\x00\x00" \
|
|
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00" \
|
|
"\x00\x00\x00\x00\x9e\x8f\xb8\x91\x00\x00\x00\x00\x01\x5b\x11\xbb" \
|
|
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
|
|
|
|
resp_str[28] = 0x01;
|
|
r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_SMB,
|
|
STREAM_TOCLIENT | STREAM_START, (uint8_t *)resp_str, sizeof(resp_str));
|
|
FAIL_IF_NOT(r == 0);
|
|
resp_str[28] = 0x04;
|
|
r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_SMB,
|
|
STREAM_TOCLIENT, (uint8_t *)resp_str, sizeof(resp_str));
|
|
FAIL_IF_NOT(r == 0);
|
|
resp_str[28] = 0x05;
|
|
r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_SMB,
|
|
STREAM_TOCLIENT, (uint8_t *)resp_str, sizeof(resp_str));
|
|
FAIL_IF_NOT(r == 0);
|
|
resp_str[28] = 0x06;
|
|
r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_SMB,
|
|
STREAM_TOCLIENT, (uint8_t *)resp_str, sizeof(resp_str));
|
|
FAIL_IF_NOT(r == 0);
|
|
resp_str[28] = 0x08;
|
|
r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_SMB,
|
|
STREAM_TOCLIENT, (uint8_t *)resp_str, sizeof(resp_str));
|
|
FAIL_IF_NOT(r == 0);
|
|
resp_str[28] = 0x02;
|
|
r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_SMB,
|
|
STREAM_TOCLIENT, (uint8_t *)resp_str, sizeof(resp_str));
|
|
FAIL_IF_NOT(r == 0);
|
|
resp_str[28] = 0x07;
|
|
r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_SMB,
|
|
STREAM_TOCLIENT, (uint8_t *)resp_str, sizeof(resp_str));
|
|
FAIL_IF_NOT(r == 0);
|
|
AppLayerParserTransactionsCleanup(f, STREAM_TOCLIENT);
|
|
|
|
UTHAppLayerParserStateGetIds(f->alparser, &ret[0], &ret[1], &ret[2], &ret[3]);
|
|
FAIL_IF_NOT(ret[0] == 2); // inspect_id[0]
|
|
FAIL_IF_NOT(ret[1] == 2); // inspect_id[1]
|
|
FAIL_IF_NOT(ret[2] == 2); // log_id
|
|
FAIL_IF_NOT(ret[3] == 2); // min_id
|
|
|
|
resp_str[28] = 0x03;
|
|
r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_SMB,
|
|
STREAM_TOCLIENT, (uint8_t *)resp_str, sizeof(resp_str));
|
|
FAIL_IF_NOT(r == 0);
|
|
AppLayerParserTransactionsCleanup(f, STREAM_TOCLIENT);
|
|
|
|
UTHAppLayerParserStateGetIds(f->alparser, &ret[0], &ret[1], &ret[2], &ret[3]);
|
|
FAIL_IF_NOT(ret[0] == 8); // inspect_id[0]
|
|
FAIL_IF_NOT(ret[1] == 8); // inspect_id[1]
|
|
FAIL_IF_NOT(ret[2] == 8); // log_id
|
|
FAIL_IF_NOT(ret[3] == 8); // min_id
|
|
|
|
req_str[28] = 0x09;
|
|
r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_SMB,
|
|
STREAM_TOSERVER | STREAM_EOF, (uint8_t *)req_str, sizeof(req_str));
|
|
FAIL_IF_NOT(r == 0);
|
|
AppLayerParserTransactionsCleanup(f, STREAM_TOSERVER);
|
|
|
|
UTHAppLayerParserStateGetIds(f->alparser, &ret[0], &ret[1], &ret[2], &ret[3]);
|
|
FAIL_IF_NOT(ret[0] == 8); // inspect_id[0] not updated by ..Cleanup() until full tx is done
|
|
FAIL_IF_NOT(ret[1] == 8); // inspect_id[1]
|
|
FAIL_IF_NOT(ret[2] == 8); // log_id
|
|
FAIL_IF_NOT(ret[3] == 8); // min_id
|
|
|
|
resp_str[28] = 0x09;
|
|
r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_SMB,
|
|
STREAM_TOCLIENT | STREAM_EOF, (uint8_t *)resp_str, sizeof(resp_str));
|
|
FAIL_IF_NOT(r == 0);
|
|
AppLayerParserTransactionsCleanup(f, STREAM_TOCLIENT);
|
|
|
|
UTHAppLayerParserStateGetIds(f->alparser, &ret[0], &ret[1], &ret[2], &ret[3]);
|
|
FAIL_IF_NOT(ret[0] == 9); // inspect_id[0]
|
|
FAIL_IF_NOT(ret[1] == 9); // inspect_id[1]
|
|
FAIL_IF_NOT(ret[2] == 9); // log_id
|
|
FAIL_IF_NOT(ret[3] == 9); // min_id
|
|
|
|
AppLayerParserThreadCtxFree(alp_tctx);
|
|
StreamTcpFreeConfig(true);
|
|
UTHFreeFlow(f);
|
|
|
|
PASS;
|
|
}
|
|
|
|
static void SMBParserRegisterTests(void)
|
|
{
|
|
UtRegisterTest("SMBParserTxCleanupTest", SMBParserTxCleanupTest);
|
|
}
|
|
|
|
#endif /* UNITTESTS */
|