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.
1593 lines
50 KiB
C
1593 lines
50 KiB
C
/* Copyright (C) 2007-2014 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
|
|
*
|
|
* \author Pablo Rincon <pablo.rincon.crespo@gmail.com>
|
|
* \author Victor Julien <victor@inliniac.net>
|
|
*
|
|
* App-layer parser for SSH protocol
|
|
*
|
|
*/
|
|
|
|
#include "suricata-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-tcp.h"
|
|
#include "stream.h"
|
|
|
|
#include "app-layer-protos.h"
|
|
#include "app-layer-parser.h"
|
|
#include "app-layer-ssh.h"
|
|
#include "rust.h"
|
|
|
|
#include "conf.h"
|
|
|
|
#include "util-spm.h"
|
|
#include "util-unittest.h"
|
|
#include "util-debug.h"
|
|
#include "flow-private.h"
|
|
|
|
#include "util-byte.h"
|
|
#include "util-memcmp.h"
|
|
|
|
/* HASSH fingerprints are disabled by default */
|
|
#define SSH_CONFIG_DEFAULT_HASSH false
|
|
|
|
static int SSHRegisterPatternsForProtocolDetection(void)
|
|
{
|
|
if (AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_SSH,
|
|
"SSH-", 4, 0, STREAM_TOSERVER) < 0)
|
|
{
|
|
return -1;
|
|
}
|
|
if (AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_SSH,
|
|
"SSH-", 4, 0, STREAM_TOCLIENT) < 0)
|
|
{
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int SSHTxLogCondition(ThreadVars * tv, const Packet * p, void *state, void *tx, uint64_t tx_id)
|
|
{
|
|
return rs_ssh_tx_get_log_condition(tx);
|
|
}
|
|
|
|
/** \brief Function to register the SSH protocol parsers and other functions
|
|
*/
|
|
void RegisterSSHParsers(void)
|
|
{
|
|
const char *proto_name = "ssh";
|
|
|
|
if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) {
|
|
AppLayerProtoDetectRegisterProtocol(ALPROTO_SSH, proto_name);
|
|
if (SSHRegisterPatternsForProtocolDetection() < 0)
|
|
return;
|
|
|
|
/* Check if we should generate Hassh fingerprints */
|
|
int enable_hassh = SSH_CONFIG_DEFAULT_HASSH;
|
|
const char *strval = NULL;
|
|
if (ConfGetValue("app-layer.protocols.ssh.hassh", &strval) != 1) {
|
|
enable_hassh = SSH_CONFIG_DEFAULT_HASSH;
|
|
} else if (strcmp(strval, "auto") == 0) {
|
|
enable_hassh = SSH_CONFIG_DEFAULT_HASSH;
|
|
} else if (ConfValIsFalse(strval)) {
|
|
enable_hassh = SSH_CONFIG_DEFAULT_HASSH;
|
|
} else if (ConfValIsTrue(strval)) {
|
|
enable_hassh = true;
|
|
}
|
|
|
|
if (RunmodeIsUnittests() || enable_hassh) {
|
|
rs_ssh_enable_hassh();
|
|
}
|
|
}
|
|
|
|
SCLogDebug("Registering Rust SSH parser.");
|
|
rs_ssh_register_parser();
|
|
|
|
|
|
#ifdef UNITTESTS
|
|
AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_SSH, SSHParserRegisterTests);
|
|
#endif
|
|
}
|
|
|
|
/* UNITTESTS */
|
|
#ifdef UNITTESTS
|
|
#include "flow-util.h"
|
|
#include "stream-tcp-util.h"
|
|
#include "util-unittest-helper.h"
|
|
|
|
static int SSHParserTestUtilCheck(const char *protoexp, const char *softexp, void *tx, uint8_t flags) {
|
|
const uint8_t *protocol = NULL;
|
|
uint32_t p_len = 0;
|
|
const uint8_t *software = NULL;
|
|
uint32_t s_len = 0;
|
|
|
|
if (rs_ssh_tx_get_protocol(tx, &protocol, &p_len, flags) != 1) {
|
|
printf("Version string not parsed correctly return: ");
|
|
return 1;
|
|
}
|
|
if (protocol == NULL) {
|
|
printf("Version string not parsed correctly NULL: ");
|
|
return 1;
|
|
}
|
|
|
|
if (p_len != strlen(protoexp)) {
|
|
printf("Version string not parsed correctly length: ");
|
|
return 1;
|
|
}
|
|
if (memcmp(protocol, protoexp, strlen(protoexp)) != 0) {
|
|
printf("Version string not parsed correctly: ");
|
|
return 1;
|
|
}
|
|
|
|
if (softexp != NULL) {
|
|
if (rs_ssh_tx_get_software(tx, &software, &s_len, flags) != 1)
|
|
return 1;
|
|
if (software == NULL)
|
|
return 1;
|
|
if (s_len != strlen(softexp)) {
|
|
printf("Software string not parsed correctly length: ");
|
|
return 1;
|
|
}
|
|
if (memcmp(software, softexp, strlen(softexp)) != 0) {
|
|
printf("Software string not parsed correctly: ");
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/** \test Send a version string in one chunk (client version str). */
|
|
static int SSHParserTest01(void)
|
|
{
|
|
int result = 0;
|
|
Flow f;
|
|
uint8_t sshbuf[] = "SSH-2.0-MySSHClient-0.5.1\n";
|
|
uint32_t sshlen = sizeof(sshbuf) - 1;
|
|
TcpSession ssn;
|
|
AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
|
|
|
|
memset(&f, 0, sizeof(f));
|
|
memset(&ssn, 0, sizeof(ssn));
|
|
FLOW_INITIALIZE(&f);
|
|
f.protoctx = (void *)&ssn;
|
|
f.alproto = ALPROTO_SSH;
|
|
|
|
StreamTcpInitConfig(true);
|
|
|
|
int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
|
|
STREAM_TOSERVER | STREAM_EOF, sshbuf, sshlen);
|
|
if (r != 0) {
|
|
printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r);
|
|
goto end;
|
|
}
|
|
|
|
void *ssh_state = f.alstate;
|
|
if (ssh_state == NULL) {
|
|
printf("no ssh state: ");
|
|
goto end;
|
|
}
|
|
|
|
void * tx = rs_ssh_state_get_tx(ssh_state, 0);
|
|
if ( rs_ssh_tx_get_alstate_progress(tx, STREAM_TOSERVER) != SshStateBannerDone ) {
|
|
printf("Client version string not parsed: ");
|
|
goto end;
|
|
}
|
|
|
|
if (SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOSERVER))
|
|
goto end;
|
|
|
|
result = 1;
|
|
end:
|
|
if (alp_tctx != NULL)
|
|
AppLayerParserThreadCtxFree(alp_tctx);
|
|
StreamTcpFreeConfig(true);
|
|
FLOW_DESTROY(&f);
|
|
return result;
|
|
}
|
|
|
|
/** \test Send a version string in one chunk but multiple lines and comments.
|
|
* (client version str)
|
|
*/
|
|
static int SSHParserTest02(void)
|
|
{
|
|
int result = 0;
|
|
Flow f;
|
|
uint8_t sshbuf[] = "SSH-2.0-MySSHClient-0.5.1 some comments...\n";
|
|
uint32_t sshlen = sizeof(sshbuf) - 1;
|
|
TcpSession ssn;
|
|
AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
|
|
|
|
memset(&f, 0, sizeof(f));
|
|
memset(&ssn, 0, sizeof(ssn));
|
|
FLOW_INITIALIZE(&f);
|
|
f.protoctx = (void *)&ssn;
|
|
f.alproto = ALPROTO_SSH;
|
|
|
|
StreamTcpInitConfig(true);
|
|
|
|
int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
|
|
STREAM_TOSERVER | STREAM_EOF, sshbuf, sshlen);
|
|
if (r != 0) {
|
|
printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r);
|
|
goto end;
|
|
}
|
|
|
|
void *ssh_state = f.alstate;
|
|
if (ssh_state == NULL) {
|
|
printf("no ssh state: ");
|
|
goto end;
|
|
}
|
|
void * tx = rs_ssh_state_get_tx(ssh_state, 0);
|
|
|
|
if ( rs_ssh_tx_get_alstate_progress(tx, STREAM_TOSERVER) != SshStateBannerDone ) {
|
|
printf("Client version string not parsed: ");
|
|
goto end;
|
|
}
|
|
if (SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOSERVER))
|
|
goto end;
|
|
|
|
result = 1;
|
|
end:
|
|
if (alp_tctx != NULL)
|
|
AppLayerParserThreadCtxFree(alp_tctx);
|
|
StreamTcpFreeConfig(true);
|
|
FLOW_DESTROY(&f);
|
|
return result;
|
|
}
|
|
|
|
/** \test Send a invalid version string in one chunk but multiple lines and comments.
|
|
* (client version str)
|
|
*/
|
|
static int SSHParserTest03(void)
|
|
{
|
|
int result = 0;
|
|
Flow f;
|
|
uint8_t sshbuf[] = "SSH-2.0 some comments...\n";
|
|
uint32_t sshlen = sizeof(sshbuf) - 1;
|
|
TcpSession ssn;
|
|
AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
|
|
|
|
memset(&f, 0, sizeof(f));
|
|
memset(&ssn, 0, sizeof(ssn));
|
|
FLOW_INITIALIZE(&f);
|
|
f.protoctx = (void *)&ssn;
|
|
f.alproto = ALPROTO_SSH;
|
|
|
|
StreamTcpInitConfig(true);
|
|
|
|
int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
|
|
STREAM_TOSERVER | STREAM_EOF, sshbuf, sshlen);
|
|
if (r == 0) {
|
|
printf("toclient chunk 1 returned %" PRId32 ", expected != 0: ", r);
|
|
goto end;
|
|
}
|
|
|
|
void *ssh_state = f.alstate;
|
|
if (ssh_state == NULL) {
|
|
printf("no ssh state: ");
|
|
goto end;
|
|
}
|
|
void * tx = rs_ssh_state_get_tx(ssh_state, 0);
|
|
|
|
if ( rs_ssh_tx_get_alstate_progress(tx, STREAM_TOSERVER) == SshStateBannerDone ) {
|
|
printf("Client version string parsed? It's not a valid string: ");
|
|
goto end;
|
|
}
|
|
const uint8_t *dummy = NULL;
|
|
uint32_t dummy_len = 0;
|
|
if (rs_ssh_tx_get_protocol(tx, &dummy, &dummy_len, STREAM_TOSERVER) != 0)
|
|
goto end;
|
|
if (rs_ssh_tx_get_software(tx, &dummy, &dummy_len, STREAM_TOSERVER) != 0)
|
|
goto end;
|
|
|
|
result = 1;
|
|
end:
|
|
if (alp_tctx != NULL)
|
|
AppLayerParserThreadCtxFree(alp_tctx);
|
|
StreamTcpFreeConfig(true);
|
|
FLOW_DESTROY(&f);
|
|
return result;
|
|
}
|
|
|
|
/** \test Send a version string in one chunk (server version str). */
|
|
static int SSHParserTest04(void)
|
|
{
|
|
int result = 0;
|
|
Flow f;
|
|
uint8_t sshbuf[] = "SSH-2.0-MySSHClient-0.5.1\n";
|
|
uint32_t sshlen = sizeof(sshbuf) - 1;
|
|
TcpSession ssn;
|
|
AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
|
|
|
|
memset(&f, 0, sizeof(f));
|
|
memset(&ssn, 0, sizeof(ssn));
|
|
FLOW_INITIALIZE(&f);
|
|
f.protoctx = (void *)&ssn;
|
|
f.alproto = ALPROTO_SSH;
|
|
|
|
StreamTcpInitConfig(true);
|
|
|
|
int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
|
|
STREAM_TOCLIENT | STREAM_EOF, sshbuf, sshlen);
|
|
if (r != 0) {
|
|
printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
|
|
goto end;
|
|
}
|
|
|
|
void *ssh_state = f.alstate;
|
|
if (ssh_state == NULL) {
|
|
printf("no ssh state: ");
|
|
goto end;
|
|
}
|
|
void * tx = rs_ssh_state_get_tx(ssh_state, 0);
|
|
|
|
if ( rs_ssh_tx_get_alstate_progress(tx, STREAM_TOCLIENT) != SshStateBannerDone ) {
|
|
printf("Client version string not parsed: ");
|
|
goto end;
|
|
}
|
|
if (SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOCLIENT))
|
|
goto end;
|
|
|
|
result = 1;
|
|
|
|
end:
|
|
if (alp_tctx != NULL)
|
|
AppLayerParserThreadCtxFree(alp_tctx);
|
|
StreamTcpFreeConfig(true);
|
|
FLOW_DESTROY(&f);
|
|
return result;
|
|
}
|
|
|
|
/** \test Send a version string in one chunk (server version str)
|
|
*/
|
|
static int SSHParserTest05(void)
|
|
{
|
|
int result = 0;
|
|
Flow f;
|
|
uint8_t sshbuf[] = "SSH-2.0-MySSHClient-0.5.1 some comments...\n";
|
|
uint32_t sshlen = sizeof(sshbuf) - 1;
|
|
TcpSession ssn;
|
|
AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
|
|
|
|
memset(&f, 0, sizeof(f));
|
|
memset(&ssn, 0, sizeof(ssn));
|
|
FLOW_INITIALIZE(&f);
|
|
f.protoctx = (void *)&ssn;
|
|
f.alproto = ALPROTO_SSH;
|
|
|
|
StreamTcpInitConfig(true);
|
|
|
|
int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
|
|
STREAM_TOCLIENT | STREAM_EOF, sshbuf, sshlen);
|
|
if (r != 0) {
|
|
printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
|
|
goto end;
|
|
}
|
|
|
|
void *ssh_state = f.alstate;
|
|
if (ssh_state == NULL) {
|
|
printf("no ssh state: ");
|
|
goto end;
|
|
}
|
|
void * tx = rs_ssh_state_get_tx(ssh_state, 0);
|
|
|
|
if ( rs_ssh_tx_get_alstate_progress(tx, STREAM_TOCLIENT) != SshStateBannerDone ) {
|
|
printf("Client version string not parsed: ");
|
|
goto end;
|
|
}
|
|
if (SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOCLIENT))
|
|
goto end;
|
|
|
|
result = 1;
|
|
end:
|
|
if (alp_tctx != NULL)
|
|
AppLayerParserThreadCtxFree(alp_tctx);
|
|
StreamTcpFreeConfig(true);
|
|
FLOW_DESTROY(&f);
|
|
return result;
|
|
}
|
|
|
|
/** \test Send a invalid version string in one chunk (server version str)
|
|
*/
|
|
static int SSHParserTest06(void)
|
|
{
|
|
int result = 0;
|
|
Flow f;
|
|
uint8_t sshbuf[] = "SSH-2.0 some comments...\n";
|
|
uint32_t sshlen = sizeof(sshbuf) - 1;
|
|
TcpSession ssn;
|
|
AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
|
|
|
|
memset(&f, 0, sizeof(f));
|
|
memset(&ssn, 0, sizeof(ssn));
|
|
FLOW_INITIALIZE(&f);
|
|
f.protoctx = (void *)&ssn;
|
|
f.alproto = ALPROTO_SSH;
|
|
|
|
StreamTcpInitConfig(true);
|
|
|
|
int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
|
|
STREAM_TOCLIENT | STREAM_EOF, sshbuf, sshlen);
|
|
if (r == 0) {
|
|
printf("toserver chunk 1 returned %" PRId32 ", expected != 0: ", r);
|
|
goto end;
|
|
}
|
|
/* Ok, it returned an error. Let's make sure we didn't parse the string at all */
|
|
|
|
void *ssh_state = f.alstate;
|
|
if (ssh_state == NULL) {
|
|
printf("no ssh state: ");
|
|
goto end;
|
|
}
|
|
void * tx = rs_ssh_state_get_tx(ssh_state, 0);
|
|
|
|
if ( rs_ssh_tx_get_alstate_progress(tx, STREAM_TOCLIENT) == SshStateBannerDone ) {
|
|
printf("Client version string parsed? It's not a valid string: ");
|
|
goto end;
|
|
}
|
|
const uint8_t *dummy = NULL;
|
|
uint32_t dummy_len = 0;
|
|
if (rs_ssh_tx_get_protocol(tx, &dummy, &dummy_len, STREAM_TOCLIENT) != 0)
|
|
goto end;
|
|
if (rs_ssh_tx_get_software(tx, &dummy, &dummy_len, STREAM_TOCLIENT) != 0)
|
|
goto end;
|
|
|
|
|
|
result = 1;
|
|
end:
|
|
if (alp_tctx != NULL)
|
|
AppLayerParserThreadCtxFree(alp_tctx);
|
|
StreamTcpFreeConfig(true);
|
|
FLOW_DESTROY(&f);
|
|
return result;
|
|
}
|
|
|
|
#define MAX_SSH_TEST_SIZE 512
|
|
|
|
static int SSHParserTest07(void)
|
|
{
|
|
TcpReassemblyThreadCtx *ra_ctx = NULL;
|
|
ThreadVars tv;
|
|
TcpSession ssn;
|
|
Flow *f = NULL;
|
|
Packet *p = NULL;
|
|
|
|
char sshbufs[2][MAX_SSH_TEST_SIZE] = {"SSH-2.", "0-MySSHClient-0.5.1\r\n"};
|
|
|
|
memset(&tv, 0x00, sizeof(tv));
|
|
|
|
StreamTcpUTInit(&ra_ctx);
|
|
StreamTcpUTInitInline();
|
|
StreamTcpUTSetupSession(&ssn);
|
|
StreamTcpUTSetupStream(&ssn.server, 1);
|
|
StreamTcpUTSetupStream(&ssn.client, 1);
|
|
|
|
f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222);
|
|
FAIL_IF_NULL(f);
|
|
f->protoctx = &ssn;
|
|
f->proto = IPPROTO_TCP;
|
|
f->alproto = ALPROTO_SSH;
|
|
|
|
p = PacketGetFromAlloc();
|
|
FAIL_IF(unlikely(p == NULL));
|
|
p->proto = IPPROTO_TCP;
|
|
p->flow = f;
|
|
|
|
uint32_t seq = 2;
|
|
for (int i=0; i<2; i++) {
|
|
FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.client, seq, (uint8_t *) sshbufs[i], strlen(sshbufs[i])) == -1);
|
|
seq += strlen(sshbufs[i]);
|
|
FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.client, p, UPDATE_DIR_PACKET) < 0);
|
|
}
|
|
|
|
void *ssh_state = f->alstate;
|
|
FAIL_IF_NULL(ssh_state);
|
|
void * tx = rs_ssh_state_get_tx(ssh_state, 0);
|
|
FAIL_IF( rs_ssh_tx_get_alstate_progress(tx, STREAM_TOSERVER) != SshStateBannerDone );
|
|
|
|
FAIL_IF(SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOSERVER));
|
|
|
|
UTHFreePacket(p);
|
|
StreamTcpUTClearSession(&ssn);
|
|
StreamTcpUTDeinit(ra_ctx);
|
|
UTHFreeFlow(f);
|
|
PASS;
|
|
}
|
|
|
|
/** \test Send a version banner in three chunks. */
|
|
static int SSHParserTest08(void)
|
|
{
|
|
TcpReassemblyThreadCtx *ra_ctx = NULL;
|
|
ThreadVars tv;
|
|
TcpSession ssn;
|
|
Flow *f = NULL;
|
|
Packet *p = NULL;
|
|
|
|
char sshbufs[3][MAX_SSH_TEST_SIZE] = {"SSH-", "2.", "0-MySSHClient-0.5.1\r\n"};
|
|
|
|
memset(&tv, 0x00, sizeof(tv));
|
|
|
|
StreamTcpUTInit(&ra_ctx);
|
|
StreamTcpUTInitInline();
|
|
StreamTcpUTSetupSession(&ssn);
|
|
StreamTcpUTSetupStream(&ssn.server, 1);
|
|
StreamTcpUTSetupStream(&ssn.client, 1);
|
|
|
|
f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222);
|
|
FAIL_IF_NULL(f);
|
|
f->protoctx = &ssn;
|
|
f->proto = IPPROTO_TCP;
|
|
f->alproto = ALPROTO_SSH;
|
|
|
|
p = PacketGetFromAlloc();
|
|
FAIL_IF(unlikely(p == NULL));
|
|
p->proto = IPPROTO_TCP;
|
|
p->flow = f;
|
|
|
|
uint32_t seq = 2;
|
|
for (int i=0; i<3; i++) {
|
|
FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.client, seq, (uint8_t *) sshbufs[i], strlen(sshbufs[i])) == -1);
|
|
seq += strlen(sshbufs[i]);
|
|
FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.client, p, UPDATE_DIR_PACKET) < 0);
|
|
}
|
|
|
|
void *ssh_state = f->alstate;
|
|
FAIL_IF_NULL(ssh_state);
|
|
void * tx = rs_ssh_state_get_tx(ssh_state, 0);
|
|
FAIL_IF( rs_ssh_tx_get_alstate_progress(tx, STREAM_TOSERVER) != SshStateBannerDone );
|
|
|
|
FAIL_IF(SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOSERVER));
|
|
|
|
UTHFreePacket(p);
|
|
StreamTcpUTClearSession(&ssn);
|
|
StreamTcpUTDeinit(ra_ctx);
|
|
UTHFreeFlow(f);
|
|
PASS;
|
|
}
|
|
|
|
static int SSHParserTest09(void)
|
|
{
|
|
TcpReassemblyThreadCtx *ra_ctx = NULL;
|
|
ThreadVars tv;
|
|
TcpSession ssn;
|
|
Flow *f = NULL;
|
|
Packet *p = NULL;
|
|
|
|
char sshbufs[2][MAX_SSH_TEST_SIZE] = {"SSH-2.", "0-MySSHClient-0.5.1\r\n"};
|
|
|
|
memset(&tv, 0x00, sizeof(tv));
|
|
|
|
StreamTcpUTInit(&ra_ctx);
|
|
StreamTcpUTInitInline();
|
|
StreamTcpUTSetupSession(&ssn);
|
|
StreamTcpUTSetupStream(&ssn.server, 1);
|
|
StreamTcpUTSetupStream(&ssn.client, 1);
|
|
|
|
f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222);
|
|
FAIL_IF_NULL(f);
|
|
f->protoctx = &ssn;
|
|
f->proto = IPPROTO_TCP;
|
|
f->alproto = ALPROTO_SSH;
|
|
|
|
p = PacketGetFromAlloc();
|
|
FAIL_IF(unlikely(p == NULL));
|
|
p->proto = IPPROTO_TCP;
|
|
p->flow = f;
|
|
|
|
uint32_t seq = 2;
|
|
for (int i=0; i<2; i++) {
|
|
FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, seq, (uint8_t *) sshbufs[i], strlen(sshbufs[i])) == -1);
|
|
seq += strlen(sshbufs[i]);
|
|
FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < 0);
|
|
}
|
|
|
|
void *ssh_state = f->alstate;
|
|
FAIL_IF_NULL(ssh_state);
|
|
void * tx = rs_ssh_state_get_tx(ssh_state, 0);
|
|
FAIL_IF( rs_ssh_tx_get_alstate_progress(tx, STREAM_TOCLIENT) != SshStateBannerDone );
|
|
|
|
FAIL_IF(SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOCLIENT));
|
|
|
|
UTHFreePacket(p);
|
|
StreamTcpUTClearSession(&ssn);
|
|
StreamTcpUTDeinit(ra_ctx);
|
|
UTHFreeFlow(f);
|
|
PASS;
|
|
}
|
|
|
|
/** \test Send a version banner in three chunks. */
|
|
static int SSHParserTest10(void)
|
|
{
|
|
TcpReassemblyThreadCtx *ra_ctx = NULL;
|
|
ThreadVars tv;
|
|
TcpSession ssn;
|
|
Flow *f = NULL;
|
|
Packet *p = NULL;
|
|
|
|
char sshbufs[3][MAX_SSH_TEST_SIZE] = {"SSH-", "2.", "0-MySSHClient-0.5.1\r\n"};
|
|
|
|
memset(&tv, 0x00, sizeof(tv));
|
|
|
|
StreamTcpUTInit(&ra_ctx);
|
|
StreamTcpUTInitInline();
|
|
StreamTcpUTSetupSession(&ssn);
|
|
StreamTcpUTSetupStream(&ssn.server, 1);
|
|
StreamTcpUTSetupStream(&ssn.client, 1);
|
|
|
|
f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222);
|
|
FAIL_IF_NULL(f);
|
|
f->protoctx = &ssn;
|
|
f->proto = IPPROTO_TCP;
|
|
f->alproto = ALPROTO_SSH;
|
|
|
|
p = PacketGetFromAlloc();
|
|
FAIL_IF(unlikely(p == NULL));
|
|
p->proto = IPPROTO_TCP;
|
|
p->flow = f;
|
|
|
|
uint32_t seq = 2;
|
|
for (int i=0; i<3; i++) {
|
|
FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, seq, (uint8_t *) sshbufs[i], strlen(sshbufs[i])) == -1);
|
|
seq += strlen(sshbufs[i]);
|
|
FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < 0);
|
|
}
|
|
|
|
void *ssh_state = f->alstate;
|
|
FAIL_IF_NULL(ssh_state);
|
|
void * tx = rs_ssh_state_get_tx(ssh_state, 0);
|
|
FAIL_IF( rs_ssh_tx_get_alstate_progress(tx, STREAM_TOCLIENT) != SshStateBannerDone );
|
|
|
|
FAIL_IF(SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOCLIENT));
|
|
|
|
UTHFreePacket(p);
|
|
StreamTcpUTClearSession(&ssn);
|
|
StreamTcpUTDeinit(ra_ctx);
|
|
UTHFreeFlow(f);
|
|
PASS;
|
|
}
|
|
|
|
/** \test Send a banner and record in three chunks. */
|
|
static int SSHParserTest11(void)
|
|
{
|
|
int result = 0;
|
|
Flow f;
|
|
uint8_t sshbuf1[] = "SSH-2.0-MySSHClient-0.5.1\r\n";
|
|
uint32_t sshlen1 = sizeof(sshbuf1) - 1;
|
|
uint8_t sshbuf2[] = { 0x00, 0x00, 0x00, 0x03, 0x01, 21, 0x00};
|
|
uint32_t sshlen2 = sizeof(sshbuf2);
|
|
TcpSession ssn;
|
|
AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
|
|
|
|
memset(&f, 0, sizeof(f));
|
|
memset(&ssn, 0, sizeof(ssn));
|
|
FLOW_INITIALIZE(&f);
|
|
f.protoctx = (void *)&ssn;
|
|
f.alproto = ALPROTO_SSH;
|
|
|
|
StreamTcpInitConfig(true);
|
|
|
|
int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
|
|
STREAM_TOSERVER, sshbuf1, sshlen1);
|
|
if (r != 0) {
|
|
printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
|
|
goto end;
|
|
}
|
|
r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER,
|
|
sshbuf2, sshlen2);
|
|
if (r != 0) {
|
|
printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
|
|
goto end;
|
|
}
|
|
|
|
void *ssh_state = f.alstate;
|
|
if (ssh_state == NULL) {
|
|
printf("no ssh state: ");
|
|
goto end;
|
|
}
|
|
void * tx = rs_ssh_state_get_tx(ssh_state, 0);
|
|
if ( rs_ssh_tx_get_flags(tx, STREAM_TOSERVER) != SshStateFinished ) {
|
|
printf("Didn't detect the msg code of new keys (ciphered data starts): ");
|
|
goto end;
|
|
}
|
|
if (SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOSERVER))
|
|
goto end;
|
|
|
|
result = 1;
|
|
end:
|
|
if (alp_tctx != NULL)
|
|
AppLayerParserThreadCtxFree(alp_tctx);
|
|
StreamTcpFreeConfig(true);
|
|
FLOW_DESTROY(&f);
|
|
return result;
|
|
}
|
|
|
|
/** \test Send a banner and 2 records record in four chunks. */
|
|
static int SSHParserTest12(void)
|
|
{
|
|
int result = 0;
|
|
Flow f;
|
|
uint8_t sshbuf1[] = "SSH-2.0-MySSHClient-0.5.1\r\n";
|
|
uint32_t sshlen1 = sizeof(sshbuf1) - 1;
|
|
uint8_t sshbuf2[] = { 0x00, 0x00, 0x00, 0x03,0x01, 17, 0x00};
|
|
uint32_t sshlen2 = sizeof(sshbuf2);
|
|
uint8_t sshbuf3[] = { 0x00, 0x00, 0x00, 0x03,0x01, 21, 0x00};
|
|
uint32_t sshlen3 = sizeof(sshbuf3);
|
|
TcpSession ssn;
|
|
AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
|
|
|
|
memset(&f, 0, sizeof(f));
|
|
memset(&ssn, 0, sizeof(ssn));
|
|
FLOW_INITIALIZE(&f);
|
|
f.protoctx = (void *)&ssn;
|
|
f.alproto = ALPROTO_SSH;
|
|
|
|
StreamTcpInitConfig(true);
|
|
|
|
int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
|
|
STREAM_TOSERVER, sshbuf1, sshlen1);
|
|
if (r != 0) {
|
|
printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
|
|
goto end;
|
|
}
|
|
r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER,
|
|
sshbuf2, sshlen2);
|
|
if (r != 0) {
|
|
printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
|
|
goto end;
|
|
}
|
|
r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER,
|
|
sshbuf3, sshlen3);
|
|
if (r != 0) {
|
|
printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
|
|
goto end;
|
|
}
|
|
|
|
void *ssh_state = f.alstate;
|
|
if (ssh_state == NULL) {
|
|
printf("no ssh state: ");
|
|
goto end;
|
|
}
|
|
void * tx = rs_ssh_state_get_tx(ssh_state, 0);
|
|
if ( rs_ssh_tx_get_flags(tx, STREAM_TOSERVER) != SshStateFinished ) {
|
|
printf("Didn't detect the msg code of new keys (ciphered data starts): ");
|
|
goto end;
|
|
}
|
|
if (SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOSERVER))
|
|
goto end;
|
|
|
|
result = 1;
|
|
end:
|
|
if (alp_tctx != NULL)
|
|
AppLayerParserThreadCtxFree(alp_tctx);
|
|
StreamTcpFreeConfig(true);
|
|
FLOW_DESTROY(&f);
|
|
return result;
|
|
}
|
|
|
|
/** \test Send a banner and 2 records record in four chunks. */
|
|
static int SSHParserTest13(void)
|
|
{
|
|
TcpReassemblyThreadCtx *ra_ctx = NULL;
|
|
ThreadVars tv;
|
|
TcpSession ssn;
|
|
Flow *f = NULL;
|
|
Packet *p = NULL;
|
|
|
|
uint8_t sshbuf1[] = "SSH-2.0-MySSHClient-0.5.1\r\n";
|
|
uint8_t sshbuf2[] = { 0x00, 0x00, 0x00, 0x02, 0x01, 17};
|
|
uint8_t sshbuf3[] = { 0x00, 0x00, 0x00, 0x02, 0x01, 21};
|
|
|
|
uint8_t* sshbufs[3] = {sshbuf1, sshbuf2, sshbuf3};
|
|
uint32_t sshlens[3] = {sizeof(sshbuf1) - 1, sizeof(sshbuf2), sizeof(sshbuf3)};
|
|
|
|
memset(&tv, 0x00, sizeof(tv));
|
|
|
|
StreamTcpUTInit(&ra_ctx);
|
|
StreamTcpUTInitInline();
|
|
StreamTcpUTSetupSession(&ssn);
|
|
StreamTcpUTSetupStream(&ssn.server, 1);
|
|
StreamTcpUTSetupStream(&ssn.client, 1);
|
|
|
|
f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222);
|
|
FAIL_IF_NULL(f);
|
|
f->protoctx = &ssn;
|
|
f->proto = IPPROTO_TCP;
|
|
f->alproto = ALPROTO_SSH;
|
|
|
|
p = PacketGetFromAlloc();
|
|
FAIL_IF(unlikely(p == NULL));
|
|
p->proto = IPPROTO_TCP;
|
|
p->flow = f;
|
|
|
|
uint32_t seq = 2;
|
|
for (int i=0; i<3; i++) {
|
|
FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.client, seq, sshbufs[i], sshlens[i]) == -1);
|
|
seq += sshlens[i];
|
|
FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.client, p, UPDATE_DIR_PACKET) < 0);
|
|
}
|
|
|
|
void *ssh_state = f->alstate;
|
|
FAIL_IF_NULL(ssh_state);
|
|
void * tx = rs_ssh_state_get_tx(ssh_state, 0);
|
|
FAIL_IF( rs_ssh_tx_get_flags(tx, STREAM_TOSERVER) != SshStateFinished );
|
|
|
|
FAIL_IF(SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOSERVER));
|
|
|
|
UTHFreePacket(p);
|
|
StreamTcpUTClearSession(&ssn);
|
|
StreamTcpUTDeinit(ra_ctx);
|
|
UTHFreeFlow(f);
|
|
PASS;
|
|
}
|
|
|
|
/** \test Send a banner and 2 records record in four chunks. */
|
|
static int SSHParserTest14(void)
|
|
{
|
|
TcpReassemblyThreadCtx *ra_ctx = NULL;
|
|
ThreadVars tv;
|
|
TcpSession ssn;
|
|
Flow *f = NULL;
|
|
Packet *p = NULL;
|
|
|
|
uint8_t sshbuf1[] = "SSH-2.0-MySSHClient-0.5.1\r\n";
|
|
uint8_t sshbuf2[] = { 0x00, 0x00, 0x00, 0x10, 0x01, 17, 0x00};
|
|
uint8_t sshbuf3[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
|
|
uint8_t sshbuf4[] = { 0x09, 0x10, 0x11, 0x12, 0x13, 0x00};
|
|
/* first byte of this record in sshbuf4 */
|
|
uint8_t sshbuf5[] = { 0x00, 0x00, 0x02, 0x01, 21};
|
|
|
|
uint8_t* sshbufs[5] = {sshbuf1, sshbuf2, sshbuf3, sshbuf4, sshbuf5};
|
|
uint32_t sshlens[5] = {sizeof(sshbuf1) - 1, sizeof(sshbuf2), sizeof(sshbuf3), sizeof(sshbuf4), sizeof(sshbuf5)};
|
|
|
|
memset(&tv, 0x00, sizeof(tv));
|
|
|
|
StreamTcpUTInit(&ra_ctx);
|
|
StreamTcpUTInitInline();
|
|
StreamTcpUTSetupSession(&ssn);
|
|
StreamTcpUTSetupStream(&ssn.server, 1);
|
|
StreamTcpUTSetupStream(&ssn.client, 1);
|
|
|
|
f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222);
|
|
FAIL_IF_NULL(f);
|
|
f->protoctx = &ssn;
|
|
f->proto = IPPROTO_TCP;
|
|
f->alproto = ALPROTO_SSH;
|
|
|
|
p = PacketGetFromAlloc();
|
|
FAIL_IF(unlikely(p == NULL));
|
|
p->proto = IPPROTO_TCP;
|
|
p->flow = f;
|
|
|
|
uint32_t seq = 2;
|
|
for (int i=0; i<5; i++) {
|
|
FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.client, seq, sshbufs[i], sshlens[i]) == -1);
|
|
seq += sshlens[i];
|
|
FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.client, p, UPDATE_DIR_PACKET) < 0);
|
|
}
|
|
|
|
void *ssh_state = f->alstate;
|
|
FAIL_IF_NULL(ssh_state);
|
|
void * tx = rs_ssh_state_get_tx(ssh_state, 0);
|
|
FAIL_IF( rs_ssh_tx_get_flags(tx, STREAM_TOSERVER) != SshStateFinished );
|
|
|
|
FAIL_IF(SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOSERVER));
|
|
|
|
UTHFreePacket(p);
|
|
StreamTcpUTClearSession(&ssn);
|
|
StreamTcpUTDeinit(ra_ctx);
|
|
UTHFreeFlow(f);
|
|
PASS;
|
|
}
|
|
|
|
/** \test Send a banner and 2 records record in four chunks. */
|
|
static int SSHParserTest15(void)
|
|
{
|
|
TcpReassemblyThreadCtx *ra_ctx = NULL;
|
|
ThreadVars tv;
|
|
TcpSession ssn;
|
|
Flow *f = NULL;
|
|
Packet *p = NULL;
|
|
|
|
uint8_t sshbuf1[] = "SSH-2.0-MySSHClient-0.5.1\r\n";
|
|
uint8_t sshbuf2[] = { 0x00, 0x00, 0x00, 0x10, 0x01, 17, 0x00};
|
|
uint8_t sshbuf3[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
|
|
uint8_t sshbuf4[] = { 0x09, 0x10, 0x11, 0x12, 0x13, 0x00};
|
|
uint8_t sshbuf5[] = { 0x00, 0x00, 0x02, 0x01, 20, 0x00, 0x00, 0x00, 0x02, 0x01, 21};
|
|
|
|
uint8_t* sshbufs[5] = {sshbuf1, sshbuf2, sshbuf3, sshbuf4, sshbuf5};
|
|
uint32_t sshlens[5] = {sizeof(sshbuf1) - 1, sizeof(sshbuf2), sizeof(sshbuf3), sizeof(sshbuf4), sizeof(sshbuf5)};
|
|
|
|
memset(&tv, 0x00, sizeof(tv));
|
|
|
|
StreamTcpUTInit(&ra_ctx);
|
|
StreamTcpUTInitInline();
|
|
StreamTcpUTSetupSession(&ssn);
|
|
StreamTcpUTSetupStream(&ssn.server, 1);
|
|
StreamTcpUTSetupStream(&ssn.client, 1);
|
|
|
|
f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222);
|
|
FAIL_IF_NULL(f);
|
|
f->protoctx = &ssn;
|
|
f->proto = IPPROTO_TCP;
|
|
f->alproto = ALPROTO_SSH;
|
|
|
|
p = PacketGetFromAlloc();
|
|
FAIL_IF(unlikely(p == NULL));
|
|
p->proto = IPPROTO_TCP;
|
|
p->flow = f;
|
|
|
|
uint32_t seq = 2;
|
|
for (int i=0; i<5; i++) {
|
|
FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.client, seq, sshbufs[i], sshlens[i]) == -1);
|
|
seq += sshlens[i];
|
|
FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.client, p, UPDATE_DIR_PACKET) < 0);
|
|
}
|
|
|
|
void *ssh_state = f->alstate;
|
|
FAIL_IF_NULL(ssh_state);
|
|
void * tx = rs_ssh_state_get_tx(ssh_state, 0);
|
|
FAIL_IF( rs_ssh_tx_get_flags(tx, STREAM_TOSERVER) != SshStateFinished );
|
|
|
|
FAIL_IF(SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOSERVER));
|
|
|
|
UTHFreePacket(p);
|
|
StreamTcpUTClearSession(&ssn);
|
|
StreamTcpUTDeinit(ra_ctx);
|
|
UTHFreeFlow(f);
|
|
PASS;
|
|
}
|
|
|
|
/** \test Send toserver a banner and record in three chunks. */
|
|
static int SSHParserTest16(void)
|
|
{
|
|
TcpReassemblyThreadCtx *ra_ctx = NULL;
|
|
ThreadVars tv;
|
|
TcpSession ssn;
|
|
Flow *f = NULL;
|
|
Packet *p = NULL;
|
|
|
|
uint8_t sshbuf1[] = "SSH-";
|
|
uint8_t sshbuf2[] = "2.0-MySSHClient-0.5.1\r\n";
|
|
uint8_t sshbuf3[] = { 0x00, 0x00, 0x00, 0x03,0x01, 21, 0x00};
|
|
|
|
uint8_t* sshbufs[3] = {sshbuf1, sshbuf2, sshbuf3};
|
|
uint32_t sshlens[3] = {sizeof(sshbuf1) - 1, sizeof(sshbuf2) - 1, sizeof(sshbuf3)};
|
|
|
|
memset(&tv, 0x00, sizeof(tv));
|
|
|
|
StreamTcpUTInit(&ra_ctx);
|
|
StreamTcpUTInitInline();
|
|
StreamTcpUTSetupSession(&ssn);
|
|
StreamTcpUTSetupStream(&ssn.server, 1);
|
|
StreamTcpUTSetupStream(&ssn.client, 1);
|
|
|
|
f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222);
|
|
FAIL_IF_NULL(f);
|
|
f->protoctx = &ssn;
|
|
f->proto = IPPROTO_TCP;
|
|
f->alproto = ALPROTO_SSH;
|
|
|
|
p = PacketGetFromAlloc();
|
|
FAIL_IF(unlikely(p == NULL));
|
|
p->proto = IPPROTO_TCP;
|
|
p->flow = f;
|
|
|
|
uint32_t seq = 2;
|
|
for (int i=0; i<3; i++) {
|
|
FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, seq, sshbufs[i], sshlens[i]) == -1);
|
|
seq += sshlens[i];
|
|
FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < 0);
|
|
}
|
|
|
|
void *ssh_state = f->alstate;
|
|
FAIL_IF_NULL(ssh_state);
|
|
void * tx = rs_ssh_state_get_tx(ssh_state, 0);
|
|
FAIL_IF( rs_ssh_tx_get_flags(tx, STREAM_TOCLIENT) != SshStateFinished );
|
|
|
|
FAIL_IF(SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOCLIENT));
|
|
|
|
UTHFreePacket(p);
|
|
StreamTcpUTClearSession(&ssn);
|
|
StreamTcpUTDeinit(ra_ctx);
|
|
UTHFreeFlow(f);
|
|
PASS;
|
|
}
|
|
|
|
/** \test Send toserver a banner and 2 records record in four chunks. */
|
|
static int SSHParserTest17(void)
|
|
{
|
|
TcpReassemblyThreadCtx *ra_ctx = NULL;
|
|
ThreadVars tv;
|
|
TcpSession ssn;
|
|
Flow *f = NULL;
|
|
Packet *p = NULL;
|
|
|
|
uint8_t sshbuf1[] = "SSH-";
|
|
uint8_t sshbuf2[] = "2.0-MySSHClient-0.5.1\r\n";
|
|
uint8_t sshbuf3[] = { 0x00, 0x00, 0x00, 0x03, 0x01, 17, 0x00};
|
|
uint8_t sshbuf4[] = { 0x00, 0x00, 0x00, 0x03, 0x01, 21, 0x00};
|
|
|
|
uint8_t* sshbufs[4] = {sshbuf1, sshbuf2, sshbuf3, sshbuf4};
|
|
uint32_t sshlens[4] = {sizeof(sshbuf1) - 1, sizeof(sshbuf2) - 1, sizeof(sshbuf3), sizeof(sshbuf4)};
|
|
|
|
memset(&tv, 0x00, sizeof(tv));
|
|
|
|
StreamTcpUTInit(&ra_ctx);
|
|
StreamTcpUTInitInline();
|
|
StreamTcpUTSetupSession(&ssn);
|
|
StreamTcpUTSetupStream(&ssn.server, 1);
|
|
StreamTcpUTSetupStream(&ssn.client, 1);
|
|
|
|
f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222);
|
|
FAIL_IF_NULL(f);
|
|
f->protoctx = &ssn;
|
|
f->proto = IPPROTO_TCP;
|
|
f->alproto = ALPROTO_SSH;
|
|
|
|
p = PacketGetFromAlloc();
|
|
FAIL_IF(unlikely(p == NULL));
|
|
p->proto = IPPROTO_TCP;
|
|
p->flow = f;
|
|
|
|
uint32_t seq = 2;
|
|
for (int i=0; i<4; i++) {
|
|
FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, seq, sshbufs[i], sshlens[i]) == -1);
|
|
seq += sshlens[i];
|
|
FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < 0);
|
|
}
|
|
|
|
void *ssh_state = f->alstate;
|
|
FAIL_IF_NULL(ssh_state);
|
|
void * tx = rs_ssh_state_get_tx(ssh_state, 0);
|
|
FAIL_IF( rs_ssh_tx_get_flags(tx, STREAM_TOCLIENT) != SshStateFinished );
|
|
|
|
FAIL_IF(SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOCLIENT));
|
|
|
|
UTHFreePacket(p);
|
|
StreamTcpUTClearSession(&ssn);
|
|
StreamTcpUTDeinit(ra_ctx);
|
|
UTHFreeFlow(f);
|
|
PASS;
|
|
}
|
|
|
|
/** \test 2 directional test */
|
|
static int SSHParserTest18(void)
|
|
{
|
|
TcpReassemblyThreadCtx *ra_ctx = NULL;
|
|
ThreadVars tv;
|
|
TcpSession ssn;
|
|
Flow *f = NULL;
|
|
Packet *p = NULL;
|
|
|
|
uint8_t server1[] = "SSH-2.0-OpenSSH_4.7p1 Debian-8ubuntu3\r\n";
|
|
uint8_t sshbuf1[] = "SSH-";
|
|
uint8_t sshbuf2[] = "2.0-MySSHClient-0.5.1\r\n";
|
|
uint8_t server2[] = { 0x00, 0x00, 0x00, 0x03, 0x01, 21, 0x00 };
|
|
uint8_t sshbuf3[] = { 0x00, 0x00, 0x00, 0x03, 0x01, 21, 0x00 };
|
|
|
|
|
|
memset(&tv, 0x00, sizeof(tv));
|
|
|
|
StreamTcpUTInit(&ra_ctx);
|
|
StreamTcpUTInitInline();
|
|
StreamTcpUTSetupSession(&ssn);
|
|
StreamTcpUTSetupStream(&ssn.server, 1);
|
|
StreamTcpUTSetupStream(&ssn.client, 1);
|
|
|
|
uint8_t* sshbufs[5] = {server1, sshbuf1, sshbuf2, server2, sshbuf3};
|
|
uint32_t sshlens[5] = {sizeof(server1) - 1, sizeof(sshbuf1) - 1, sizeof(sshbuf2) -1, sizeof(server2) - 1, sizeof(sshbuf3)};
|
|
bool sshdirs[5] = {true, false, false, true, false};
|
|
|
|
f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222);
|
|
FAIL_IF_NULL(f);
|
|
f->protoctx = &ssn;
|
|
f->proto = IPPROTO_TCP;
|
|
f->alproto = ALPROTO_SSH;
|
|
|
|
p = PacketGetFromAlloc();
|
|
FAIL_IF(unlikely(p == NULL));
|
|
p->proto = IPPROTO_TCP;
|
|
p->flow = f;
|
|
|
|
uint32_t seqcli = 2;
|
|
uint32_t seqsrv = 2;
|
|
for (int i=0; i<5; i++) {
|
|
if (sshdirs[i]) {
|
|
FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, seqsrv, sshbufs[i], sshlens[i]) == -1);
|
|
seqsrv += sshlens[i];
|
|
FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < 0);
|
|
} else {
|
|
FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.client, seqcli, sshbufs[i], sshlens[i]) == -1);
|
|
seqcli += sshlens[i];
|
|
FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.client, p, UPDATE_DIR_PACKET) < 0);
|
|
}
|
|
}
|
|
|
|
void *ssh_state = f->alstate;
|
|
FAIL_IF_NULL(ssh_state);
|
|
void * tx = rs_ssh_state_get_tx(ssh_state, 0);
|
|
FAIL_IF( rs_ssh_tx_get_flags(tx, STREAM_TOCLIENT) != SshStateFinished );
|
|
|
|
FAIL_IF(!(AppLayerParserStateIssetFlag(f->alparser, APP_LAYER_PARSER_NO_INSPECTION)));
|
|
|
|
UTHFreePacket(p);
|
|
StreamTcpUTClearSession(&ssn);
|
|
StreamTcpUTDeinit(ra_ctx);
|
|
UTHFreeFlow(f);
|
|
PASS;
|
|
}
|
|
|
|
/** \test Really long banner handling: bannel exactly 255 */
|
|
static int SSHParserTest19(void)
|
|
{
|
|
TcpReassemblyThreadCtx *ra_ctx = NULL;
|
|
ThreadVars tv;
|
|
TcpSession ssn;
|
|
Flow *f = NULL;
|
|
Packet *p = NULL;
|
|
|
|
uint8_t sshbuf1[] = "SSH-";
|
|
uint8_t sshbuf2[] = "2.0-";
|
|
uint8_t sshbuf3[] = "abcdefghijklmnopqrstuvwxyz"
|
|
"abcdefghijklmnopqrstuvwxyz"//60
|
|
"abcdefghijklmnopqrstuvwxyz"
|
|
"abcdefghijklmnopqrstuvwxyz"//112
|
|
"abcdefghijklmnopqrstuvwxyz"
|
|
"abcdefghijklmnopqrstuvwxyz"//164
|
|
"abcdefghijklmnopqrstuvwxyz"
|
|
"abcdefghijklmnopqrstuvwxyz"//216
|
|
"abcdefghijklmnopqrstuvwxyz"//242
|
|
"abcdefghijkl\r";//255
|
|
uint8_t sshbuf4[] = { 0x00, 0x00, 0x00, 0x03, 0x01, 21, 0x00};
|
|
|
|
uint8_t* sshbufs[4] = {sshbuf1, sshbuf2, sshbuf3, sshbuf4};
|
|
uint32_t sshlens[4] = {sizeof(sshbuf1) - 1, sizeof(sshbuf2) - 1, sizeof(sshbuf3) - 1, sizeof(sshbuf4)};
|
|
|
|
memset(&tv, 0x00, sizeof(tv));
|
|
|
|
StreamTcpUTInit(&ra_ctx);
|
|
StreamTcpUTInitInline();
|
|
StreamTcpUTSetupSession(&ssn);
|
|
StreamTcpUTSetupStream(&ssn.server, 1);
|
|
StreamTcpUTSetupStream(&ssn.client, 1);
|
|
|
|
f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222);
|
|
FAIL_IF_NULL(f);
|
|
f->protoctx = &ssn;
|
|
f->proto = IPPROTO_TCP;
|
|
f->alproto = ALPROTO_SSH;
|
|
|
|
p = PacketGetFromAlloc();
|
|
FAIL_IF(unlikely(p == NULL));
|
|
p->proto = IPPROTO_TCP;
|
|
p->flow = f;
|
|
|
|
uint32_t seq = 2;
|
|
for (int i=0; i<4; i++) {
|
|
FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, seq, sshbufs[i], sshlens[i]) == -1);
|
|
seq += sshlens[i];
|
|
FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < 0);
|
|
}
|
|
|
|
void *ssh_state = f->alstate;
|
|
FAIL_IF_NULL(ssh_state);
|
|
void * tx = rs_ssh_state_get_tx(ssh_state, 0);
|
|
FAIL_IF( rs_ssh_tx_get_flags(tx, STREAM_TOCLIENT) != SshStateFinished );
|
|
|
|
sshbuf3[sizeof(sshbuf3) - 2] = 0;
|
|
FAIL_IF(SSHParserTestUtilCheck("2.0", (char *)sshbuf3, tx, STREAM_TOCLIENT));
|
|
|
|
UTHFreePacket(p);
|
|
StreamTcpUTClearSession(&ssn);
|
|
StreamTcpUTDeinit(ra_ctx);
|
|
UTHFreeFlow(f);
|
|
PASS;
|
|
}
|
|
|
|
/** \test Really long banner handling: banner exactly 255,
|
|
* followed by malformed record */
|
|
static int SSHParserTest20(void)
|
|
{
|
|
TcpReassemblyThreadCtx *ra_ctx = NULL;
|
|
ThreadVars tv;
|
|
TcpSession ssn;
|
|
Flow *f = NULL;
|
|
Packet *p = NULL;
|
|
|
|
uint8_t sshbuf1[] = "SSH-";
|
|
uint8_t sshbuf2[] = "2.0-";
|
|
uint8_t sshbuf3[] = "abcdefghijklmnopqrstuvwxyz"
|
|
"abcdefghijklmnopqrstuvwxyz"//60
|
|
"abcdefghijklmnopqrstuvwxyz"
|
|
"abcdefghijklmnopqrstuvwxyz"//112
|
|
"abcdefghijklmnopqrstuvwxyz"
|
|
"abcdefghijklmnopqrstuvwxyz"//164
|
|
"abcdefghijklmnopqrstuvwxyz"
|
|
"abcdefghijklmnopqrstuvwxyz"//216
|
|
"abcdefghijklmnopqrstuvwxyz"//242
|
|
"abcdefghijklm\r";//256
|
|
uint8_t sshbuf4[] = {'a','b','c','d','e','f', '\r',
|
|
0x00, 0x00, 0x00, 0x06, 0x01, 21, 0x00, 0x00, 0x00};
|
|
|
|
uint8_t* sshbufs[4] = {sshbuf1, sshbuf2, sshbuf3, sshbuf4};
|
|
uint32_t sshlens[4] = {sizeof(sshbuf1) - 1, sizeof(sshbuf2) - 1, sizeof(sshbuf3) - 1, sizeof(sshbuf4) - 1};
|
|
|
|
memset(&tv, 0x00, sizeof(tv));
|
|
|
|
StreamTcpUTInit(&ra_ctx);
|
|
StreamTcpUTInitInline();
|
|
StreamTcpUTSetupSession(&ssn);
|
|
StreamTcpUTSetupStream(&ssn.server, 1);
|
|
StreamTcpUTSetupStream(&ssn.client, 1);
|
|
|
|
f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222);
|
|
FAIL_IF_NULL(f);
|
|
f->protoctx = &ssn;
|
|
f->proto = IPPROTO_TCP;
|
|
f->alproto = ALPROTO_SSH;
|
|
|
|
p = PacketGetFromAlloc();
|
|
FAIL_IF(unlikely(p == NULL));
|
|
p->proto = IPPROTO_TCP;
|
|
p->flow = f;
|
|
|
|
uint32_t seq = 2;
|
|
for (int i=0; i<4; i++) {
|
|
FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, seq, sshbufs[i], sshlens[i]) == -1);
|
|
seq += sshlens[i];
|
|
FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < 0);
|
|
}
|
|
|
|
void *ssh_state = f->alstate;
|
|
FAIL_IF_NULL(ssh_state);
|
|
void * tx = rs_ssh_state_get_tx(ssh_state, 0);
|
|
FAIL_IF( rs_ssh_tx_get_flags(tx, STREAM_TOCLIENT) != SshStateFinished );
|
|
|
|
FAIL_IF(SSHParserTestUtilCheck("2.0", NULL, tx, STREAM_TOCLIENT));
|
|
|
|
UTHFreePacket(p);
|
|
StreamTcpUTClearSession(&ssn);
|
|
StreamTcpUTDeinit(ra_ctx);
|
|
UTHFreeFlow(f);
|
|
PASS;
|
|
}
|
|
|
|
/** \test Fragmented banner handling: chunk has final part of bannel plus
|
|
* a record. */
|
|
static int SSHParserTest21(void)
|
|
{
|
|
TcpReassemblyThreadCtx *ra_ctx = NULL;
|
|
ThreadVars tv;
|
|
TcpSession ssn;
|
|
Flow *f = NULL;
|
|
Packet *p = NULL;
|
|
|
|
uint8_t sshbuf1[] = "SSH-";
|
|
uint8_t sshbuf2[] = "2.0-";
|
|
uint8_t sshbuf3[] = "abcdefghijklmnopqrstuvwxyz"
|
|
"abcdefghijklmnopqrstuvwxyz"//60
|
|
"abcdefghijklmnopqrstuvwxyz"
|
|
"abcdefghijklmnopqrstuvwxyz"//112
|
|
"abcdefghijklmnopqrstuvwxyz"
|
|
"abcdefghijklmnopqrstuvwxyz"//164
|
|
"abcdefghijklmnopqrstuvwxyz"
|
|
"abcdefghijklmnopqrstuvwxyz"//216
|
|
"abcdefghijklmnopqrstuvwxy";//241
|
|
uint8_t sshbuf4[] = {'l','i','b','s','s','h', '\r',
|
|
0x00, 0x00, 0x00, 0x06, 0x01, 21, 0x00, 0x00, 0x00};
|
|
|
|
uint8_t* sshbufs[4] = {sshbuf1, sshbuf2, sshbuf3, sshbuf4};
|
|
uint32_t sshlens[4] = {sizeof(sshbuf1) - 1, sizeof(sshbuf2) - 1, sizeof(sshbuf3) - 1, sizeof(sshbuf4)};
|
|
|
|
memset(&tv, 0x00, sizeof(tv));
|
|
|
|
StreamTcpUTInit(&ra_ctx);
|
|
StreamTcpUTInitInline();
|
|
StreamTcpUTSetupSession(&ssn);
|
|
StreamTcpUTSetupStream(&ssn.server, 1);
|
|
StreamTcpUTSetupStream(&ssn.client, 1);
|
|
|
|
f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222);
|
|
FAIL_IF_NULL(f);
|
|
f->protoctx = &ssn;
|
|
f->proto = IPPROTO_TCP;
|
|
f->alproto = ALPROTO_SSH;
|
|
|
|
p = PacketGetFromAlloc();
|
|
FAIL_IF(unlikely(p == NULL));
|
|
p->proto = IPPROTO_TCP;
|
|
p->flow = f;
|
|
|
|
uint32_t seq = 2;
|
|
for (int i=0; i<4; i++) {
|
|
FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, seq, sshbufs[i], sshlens[i]) == -1);
|
|
seq += sshlens[i];
|
|
FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < 0);
|
|
}
|
|
|
|
void *ssh_state = f->alstate;
|
|
FAIL_IF_NULL(ssh_state);
|
|
void * tx = rs_ssh_state_get_tx(ssh_state, 0);
|
|
FAIL_IF( rs_ssh_tx_get_flags(tx, STREAM_TOCLIENT) != SshStateFinished );
|
|
|
|
FAIL_IF(SSHParserTestUtilCheck("2.0", NULL, tx, STREAM_TOCLIENT));
|
|
|
|
UTHFreePacket(p);
|
|
StreamTcpUTClearSession(&ssn);
|
|
StreamTcpUTDeinit(ra_ctx);
|
|
UTHFreeFlow(f);
|
|
PASS;
|
|
}
|
|
|
|
/** \test Fragmented banner handling: chunk has final part of bannel plus
|
|
* a record. */
|
|
static int SSHParserTest22(void)
|
|
{
|
|
TcpReassemblyThreadCtx *ra_ctx = NULL;
|
|
ThreadVars tv;
|
|
TcpSession ssn;
|
|
Flow *f = NULL;
|
|
Packet *p = NULL;
|
|
|
|
uint8_t sshbuf1[] = "SSH-";
|
|
uint8_t sshbuf2[] = "2.0-";
|
|
uint8_t sshbuf3[] = {
|
|
'l', 'i', 'b', 's', 's', 'h', '\r', //7
|
|
|
|
0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, //50
|
|
|
|
0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, //100
|
|
|
|
0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, //150
|
|
|
|
0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, //200
|
|
|
|
0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, //250
|
|
|
|
0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x06, 0x01, 21, 0x00, 0x00, 0x00, 0x00, //300
|
|
};
|
|
|
|
|
|
uint8_t* sshbufs[3] = {sshbuf1, sshbuf2, sshbuf3};
|
|
uint32_t sshlens[3] = {sizeof(sshbuf1) - 1, sizeof(sshbuf2) - 1, sizeof(sshbuf3) - 1};
|
|
|
|
memset(&tv, 0x00, sizeof(tv));
|
|
|
|
StreamTcpUTInit(&ra_ctx);
|
|
StreamTcpUTInitInline();
|
|
StreamTcpUTSetupSession(&ssn);
|
|
StreamTcpUTSetupStream(&ssn.server, 1);
|
|
StreamTcpUTSetupStream(&ssn.client, 1);
|
|
|
|
f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222);
|
|
FAIL_IF_NULL(f);
|
|
f->protoctx = &ssn;
|
|
f->proto = IPPROTO_TCP;
|
|
f->alproto = ALPROTO_SSH;
|
|
|
|
p = PacketGetFromAlloc();
|
|
FAIL_IF(unlikely(p == NULL));
|
|
p->proto = IPPROTO_TCP;
|
|
p->flow = f;
|
|
|
|
uint32_t seq = 2;
|
|
for (int i=0; i<3; i++) {
|
|
FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, seq, sshbufs[i], sshlens[i]) == -1);
|
|
seq += sshlens[i];
|
|
FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < 0);
|
|
}
|
|
|
|
void *ssh_state = f->alstate;
|
|
FAIL_IF_NULL(ssh_state);
|
|
void * tx = rs_ssh_state_get_tx(ssh_state, 0);
|
|
FAIL_IF( rs_ssh_tx_get_flags(tx, STREAM_TOCLIENT) != SshStateFinished );
|
|
|
|
FAIL_IF(SSHParserTestUtilCheck("2.0", "libssh", tx, STREAM_TOCLIENT));
|
|
|
|
UTHFreePacket(p);
|
|
StreamTcpUTClearSession(&ssn);
|
|
StreamTcpUTDeinit(ra_ctx);
|
|
UTHFreeFlow(f);
|
|
PASS;
|
|
}
|
|
|
|
/** \test Send a version string in one chunk (client version str). */
|
|
static int SSHParserTest23(void)
|
|
{
|
|
int result = 0;
|
|
Flow f;
|
|
uint8_t sshbuf[] = "SSH-2.0\r-MySSHClient-0.5.1\n";
|
|
uint32_t sshlen = sizeof(sshbuf) - 1;
|
|
TcpSession ssn;
|
|
AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
|
|
|
|
memset(&f, 0, sizeof(f));
|
|
memset(&ssn, 0, sizeof(ssn));
|
|
FLOW_INITIALIZE(&f);
|
|
f.protoctx = (void *)&ssn;
|
|
f.alproto = ALPROTO_SSH;
|
|
|
|
StreamTcpInitConfig(true);
|
|
|
|
int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
|
|
STREAM_TOSERVER | STREAM_EOF, sshbuf, sshlen);
|
|
if (r == 0) {
|
|
printf("toclient chunk 1 returned 0 expected non null: ");
|
|
goto end;
|
|
}
|
|
|
|
result = 1;
|
|
end:
|
|
if (alp_tctx != NULL)
|
|
AppLayerParserThreadCtxFree(alp_tctx);
|
|
StreamTcpFreeConfig(true);
|
|
FLOW_DESTROY(&f);
|
|
return result;
|
|
}
|
|
|
|
/** \test Send a version string in one chunk (client version str). */
|
|
static int SSHParserTest24(void)
|
|
{
|
|
int result = 0;
|
|
Flow f;
|
|
uint8_t sshbuf[] = "SSH-2.0-\rMySSHClient-0.5.1\n";
|
|
uint32_t sshlen = sizeof(sshbuf) - 1;
|
|
TcpSession ssn;
|
|
AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
|
|
|
|
memset(&f, 0, sizeof(f));
|
|
memset(&ssn, 0, sizeof(ssn));
|
|
FLOW_INITIALIZE(&f);
|
|
f.protoctx = (void *)&ssn;
|
|
f.alproto = ALPROTO_SSH;
|
|
|
|
StreamTcpInitConfig(true);
|
|
|
|
int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
|
|
STREAM_TOSERVER | STREAM_EOF, sshbuf, sshlen);
|
|
if (r != 0) {
|
|
printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r);
|
|
goto end;
|
|
}
|
|
|
|
void *ssh_state = f.alstate;
|
|
if (ssh_state == NULL) {
|
|
printf("no ssh state: ");
|
|
goto end;
|
|
}
|
|
void * tx = rs_ssh_state_get_tx(ssh_state, 0);
|
|
if ( rs_ssh_tx_get_flags(tx, STREAM_TOSERVER) != SshStateBannerDone ) {
|
|
printf("Didn't detect the msg code of new keys (ciphered data starts): ");
|
|
goto end;
|
|
}
|
|
if (SSHParserTestUtilCheck("2.0", NULL, tx, STREAM_TOSERVER))
|
|
goto end;
|
|
|
|
result = 1;
|
|
end:
|
|
if (alp_tctx != NULL)
|
|
AppLayerParserThreadCtxFree(alp_tctx);
|
|
StreamTcpFreeConfig(true);
|
|
FLOW_DESTROY(&f);
|
|
return result;
|
|
}
|
|
|
|
/** \test Send a malformed banner */
|
|
static int SSHParserTest25(void)
|
|
{
|
|
Flow f;
|
|
uint8_t sshbuf[] = "\n";
|
|
uint32_t sshlen = sizeof(sshbuf) - 1;
|
|
TcpSession ssn;
|
|
AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
|
|
FAIL_IF_NULL(alp_tctx);
|
|
|
|
memset(&f, 0, sizeof(f));
|
|
memset(&ssn, 0, sizeof(ssn));
|
|
FLOW_INITIALIZE(&f);
|
|
f.protoctx = (void *)&ssn;
|
|
f.alproto = ALPROTO_SSH;
|
|
|
|
StreamTcpInitConfig(true);
|
|
|
|
int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
|
|
STREAM_TOSERVER | STREAM_EOF, sshbuf, sshlen);
|
|
FAIL_IF(r != -1);
|
|
|
|
void *ssh_state = f.alstate;
|
|
FAIL_IF_NULL(ssh_state);
|
|
void * tx = rs_ssh_state_get_tx(ssh_state, 0);
|
|
FAIL_IF( rs_ssh_tx_get_flags(tx, STREAM_TOSERVER) == SshStateBannerDone );
|
|
const uint8_t *dummy = NULL;
|
|
uint32_t dummy_len = 0;
|
|
FAIL_IF (rs_ssh_tx_get_software(tx, &dummy, &dummy_len, STREAM_TOCLIENT) != 0);
|
|
|
|
AppLayerParserThreadCtxFree(alp_tctx);
|
|
StreamTcpFreeConfig(true);
|
|
FLOW_DESTROY(&f);
|
|
PASS;
|
|
}
|
|
|
|
#endif /* UNITTESTS */
|
|
|
|
void SSHParserRegisterTests(void)
|
|
{
|
|
#ifdef UNITTESTS
|
|
UtRegisterTest("SSHParserTest01 - ToServer", SSHParserTest01);
|
|
UtRegisterTest("SSHParserTest02 - ToServer", SSHParserTest02);
|
|
UtRegisterTest("SSHParserTest03 - ToServer", SSHParserTest03);
|
|
UtRegisterTest("SSHParserTest04 - ToClient", SSHParserTest04);
|
|
UtRegisterTest("SSHParserTest05 - ToClient", SSHParserTest05);
|
|
UtRegisterTest("SSHParserTest06 - ToClient", SSHParserTest06);
|
|
UtRegisterTest("SSHParserTest07 - ToServer 2 chunks", SSHParserTest07);
|
|
UtRegisterTest("SSHParserTest08 - ToServer 3 chunks", SSHParserTest08);
|
|
UtRegisterTest("SSHParserTest09 - ToClient 2 chunks", SSHParserTest09);
|
|
UtRegisterTest("SSHParserTest10 - ToClient 3 chunks", SSHParserTest10);
|
|
UtRegisterTest("SSHParserTest11 - ToClient 4 chunks", SSHParserTest11);
|
|
UtRegisterTest("SSHParserTest12 - ToClient 4 chunks", SSHParserTest12);
|
|
UtRegisterTest("SSHParserTest13 - ToClient 4 chunks", SSHParserTest13);
|
|
UtRegisterTest("SSHParserTest14 - ToClient 4 chunks", SSHParserTest14);
|
|
UtRegisterTest("SSHParserTest15", SSHParserTest15);
|
|
UtRegisterTest("SSHParserTest16", SSHParserTest16);
|
|
UtRegisterTest("SSHParserTest17", SSHParserTest17);
|
|
UtRegisterTest("SSHParserTest18", SSHParserTest18);
|
|
UtRegisterTest("SSHParserTest19", SSHParserTest19);
|
|
UtRegisterTest("SSHParserTest20", SSHParserTest20);
|
|
UtRegisterTest("SSHParserTest21", SSHParserTest21);
|
|
UtRegisterTest("SSHParserTest22", SSHParserTest22);
|
|
UtRegisterTest("SSHParserTest23", SSHParserTest23);
|
|
UtRegisterTest("SSHParserTest24", SSHParserTest24);
|
|
UtRegisterTest("SSHParserTest25", SSHParserTest25);
|
|
#endif /* UNITTESTS */
|
|
}
|
|
|