Coverage Report

Created: 2026-11-12 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata8/src/detect-ssh-hassh.c
Line
Count
Source
1
/* Copyright (C) 2007-2020 Open Information Security Foundation
2
 *
3
 * You can copy, redistribute or modify this Program under the terms of
4
 * the GNU General Public License version 2 as published by the Free
5
 * Software Foundation.
6
 *
7
 * This program is distributed in the hope that it will be useful,
8
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 * GNU General Public License for more details.
11
 *
12
 * You should have received a copy of the GNU General Public License
13
 * version 2 along with this program; if not, write to the Free Software
14
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15
 * 02110-1301, USA.
16
 */
17
18
/**
19
 * \file
20
 *
21
 * \author Vadym Malakhatko <v.malakhatko@sirinsoftware.com>
22
 */
23
24
#include "suricata-common.h"
25
#include "threads.h"
26
#include "decode.h"
27
28
#include "detect.h"
29
#include "detect-parse.h"
30
#include "detect-content.h"
31
32
#include "detect-engine.h"
33
#include "detect-engine-buffer.h"
34
#include "detect-engine-mpm.h"
35
#include "detect-engine-state.h"
36
#include "detect-engine-prefilter.h"
37
38
#include "flow.h"
39
#include "flow-var.h"
40
#include "flow-util.h"
41
42
#include "util-debug.h"
43
#include "util-unittest.h"
44
#include "util-unittest-helper.h"
45
#include "stream-tcp.h"
46
#include "app-layer.h"
47
#include "app-layer-parser.h"
48
#include "app-layer-ssh.h"
49
#include "detect-ssh-hassh.h"
50
#include "rust.h"
51
52
53
5
#define KEYWORD_NAME "ssh.hassh"
54
5
#define KEYWORD_ALIAS "ssh-hassh"
55
5
#define KEYWORD_DOC "ssh-keywords.html#hassh"
56
35
#define BUFFER_NAME "ssh.hassh"
57
5
#define BUFFER_DESC "Ssh Client Fingerprinting For Ssh Clients "
58
static int g_ssh_hassh_buffer_id = 0;
59
60
61
static InspectionBuffer *GetSshData(DetectEngineThreadCtx *det_ctx,
62
        const DetectEngineTransforms *transforms, Flow *_f,
63
        const uint8_t flow_flags, void *txv, const int list_id)
64
0
{
65
66
0
    SCEnter();
67
68
0
    InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
69
70
0
    if (buffer->inspect == NULL) {
71
0
        const uint8_t *hassh = NULL;
72
0
        uint32_t b_len = 0;
73
74
0
        if (SCSshTxGetHassh(txv, &hassh, &b_len, flow_flags) != 1)
75
0
            return NULL;
76
0
        if (hassh == NULL || b_len == 0) {
77
0
            SCLogDebug("SSH hassh not set");
78
0
            return NULL;
79
0
        }
80
81
0
        InspectionBufferSetupAndApplyTransforms(det_ctx, list_id, buffer, hassh, b_len, transforms);
82
0
    }
83
84
0
    return buffer;
85
0
}
86
87
/**
88
 * \brief this function setup the hassh modifier keyword used in the rule
89
 *
90
 * \param de_ctx Pointer to the Detection Engine Context
91
 * \param s      Pointer to the Signature to which the current keyword belongs
92
 * \param str    Should hold an empty string always
93
 *
94
 * \retval 0  On success
95
 * \retval -1 On failure
96
 * \retval -2 on failure that should be silent after the first
97
 */
98
static int DetectSshHasshSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
99
1.25k
{
100
1.25k
    if (SCDetectBufferSetActiveList(de_ctx, s, g_ssh_hassh_buffer_id) < 0)
101
6
        return -1;
102
103
1.24k
    if (SCDetectSignatureSetAppProto(s, ALPROTO_SSH) < 0)
104
18
        return -1;
105
        
106
    /* try to enable Hassh */
107
1.22k
    SCSshEnableHassh();
108
109
    /* Check if Hassh is disabled */
110
1.22k
    if (!RunmodeIsUnittests() && !SCSshHasshIsEnabled()) {
111
0
        if (!SigMatchSilentErrorEnabled(de_ctx, DETECT_SSH_HASSH)) {
112
0
            SCLogError("hassh support is not enabled");
113
0
        }
114
0
        return -2;
115
0
    }
116
117
1.22k
    return 0;
118
119
1.22k
}
120
121
static void DetectSshHasshHashSetupCallback(const DetectEngineCtx *de_ctx,
122
                                          Signature *s)
123
730
{
124
3.58k
    for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
125
2.85k
        if (s->init_data->buffers[x].id != (uint32_t)g_ssh_hassh_buffer_id)
126
2.13k
            continue;
127
724
        SigMatch *sm = s->init_data->buffers[x].head;
128
4.83k
        for (; sm != NULL; sm = sm->next) {
129
4.11k
            if (sm->type != DETECT_CONTENT)
130
326
                continue;
131
132
3.78k
            DetectContentData *cd = (DetectContentData *)sm->ctx;
133
134
3.78k
            uint32_t u;
135
68.6k
            for (u = 0; u < cd->content_len; u++) {
136
64.8k
                if (isupper(cd->content[u])) {
137
6.47k
                    cd->content[u] = u8_tolower(cd->content[u]);
138
6.47k
                }
139
64.8k
            }
140
141
3.78k
            SpmDestroyCtx(cd->spm_ctx);
142
3.78k
            cd->spm_ctx =
143
3.78k
                    SpmInitCtx(cd->content, cd->content_len, 1, de_ctx->spm_global_thread_ctx);
144
3.78k
        }
145
724
    }
146
730
}
147
148
/**
149
 * \brief Registration function for hassh keyword.
150
 */
151
void DetectSshHasshRegister(void) 
152
5
{
153
5
    sigmatch_table[DETECT_SSH_HASSH].name = KEYWORD_NAME;
154
5
    sigmatch_table[DETECT_SSH_HASSH].alias = KEYWORD_ALIAS;
155
5
    sigmatch_table[DETECT_SSH_HASSH].desc = BUFFER_NAME " sticky buffer";
156
5
    sigmatch_table[DETECT_SSH_HASSH].url = "/rules/" KEYWORD_DOC;
157
5
    sigmatch_table[DETECT_SSH_HASSH].Setup = DetectSshHasshSetup;
158
5
    sigmatch_table[DETECT_SSH_HASSH].flags |= SIGMATCH_INFO_STICKY_BUFFER | SIGMATCH_NOOPT;
159
160
5
    DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister,
161
5
            GetSshData, ALPROTO_SSH, SshStateBannerDone),
162
5
            DetectAppLayerInspectEngineRegister(BUFFER_NAME, ALPROTO_SSH, SIG_FLAG_TOSERVER,
163
5
                    SshStateBannerDone, DetectEngineInspectBufferGeneric, GetSshData);
164
5
    DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC);
165
166
5
    g_ssh_hassh_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME);
167
168
5
    DetectBufferTypeRegisterSetupCallback(BUFFER_NAME, DetectSshHasshHashSetupCallback);
169
5
    DetectBufferTypeRegisterValidateCallback(BUFFER_NAME, DetectMd5ValidateCallback);
170
5
}
171