/src/suricata7/src/detect-transform-xor.c
Line | Count | Source |
1 | | /* Copyright (C) 2021 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 Philippe Antoine <contact@catenacyber.fr> |
22 | | * |
23 | | * Implements the xor transform keyword with option support |
24 | | */ |
25 | | |
26 | | #include "suricata-common.h" |
27 | | #include "detect.h" |
28 | | #include "detect-engine.h" |
29 | | #include "detect-parse.h" |
30 | | #include "detect-transform-xor.h" |
31 | | |
32 | | typedef struct DetectTransformXorData { |
33 | | uint8_t *key; |
34 | | // limit the key length |
35 | | uint8_t length; |
36 | | } DetectTransformXorData; |
37 | | |
38 | | static int DetectTransformXorSetup(DetectEngineCtx *, Signature *, const char *); |
39 | | static void DetectTransformXorFree(DetectEngineCtx *, void *); |
40 | | static void DetectTransformXor(InspectionBuffer *buffer, void *options); |
41 | | #ifdef UNITTESTS |
42 | | void DetectTransformXorRegisterTests(void); |
43 | | #endif |
44 | | |
45 | | void DetectTransformXorRegister(void) |
46 | 34 | { |
47 | 34 | sigmatch_table[DETECT_TRANSFORM_XOR].name = "xor"; |
48 | 34 | sigmatch_table[DETECT_TRANSFORM_XOR].desc = "modify buffer via XOR decoding before inspection"; |
49 | 34 | sigmatch_table[DETECT_TRANSFORM_XOR].url = "/rules/transforms.html#xor"; |
50 | 34 | sigmatch_table[DETECT_TRANSFORM_XOR].Transform = DetectTransformXor; |
51 | 34 | sigmatch_table[DETECT_TRANSFORM_XOR].Free = DetectTransformXorFree; |
52 | 34 | sigmatch_table[DETECT_TRANSFORM_XOR].Setup = DetectTransformXorSetup; |
53 | | #ifdef UNITTESTS |
54 | | sigmatch_table[DETECT_TRANSFORM_XOR].RegisterTests = DetectTransformXorRegisterTests; |
55 | | #endif |
56 | 34 | sigmatch_table[DETECT_TRANSFORM_XOR].flags |= SIGMATCH_QUOTES_MANDATORY; |
57 | 34 | } |
58 | | |
59 | | static void DetectTransformXorFree(DetectEngineCtx *de_ctx, void *ptr) |
60 | 1.10k | { |
61 | 1.10k | if (ptr != NULL) { |
62 | 1.10k | DetectTransformXorData *pxd = (DetectTransformXorData *)ptr; |
63 | 1.10k | SCFree(pxd->key); |
64 | 1.10k | SCFree(pxd); |
65 | 1.10k | } |
66 | 1.10k | } |
67 | | |
68 | | /** |
69 | | * \internal |
70 | | * \brief Apply the xor keyword to the last pattern match |
71 | | * \param det_ctx detection engine ctx |
72 | | * \param s signature |
73 | | * \param optstr options string |
74 | | * \retval 0 ok |
75 | | * \retval -1 failure |
76 | | */ |
77 | | static int DetectTransformXorSetup(DetectEngineCtx *de_ctx, Signature *s, const char *optstr) |
78 | 1.10k | { |
79 | 1.10k | SCEnter(); |
80 | | |
81 | | // Create pxd from optstr |
82 | 1.10k | DetectTransformXorData *pxd = SCCalloc(1, sizeof(*pxd)); |
83 | 1.10k | if (pxd == NULL) { |
84 | 0 | SCLogError("memory allocation failed"); |
85 | 0 | SCReturnInt(-1); |
86 | 0 | } |
87 | | |
88 | 1.10k | size_t keylen = strlen(optstr); |
89 | 1.10k | if (keylen % 2 == 1) { |
90 | 386 | SCLogError("XOR transform key's length must be an even number"); |
91 | 386 | DetectTransformXorFree(de_ctx, pxd); |
92 | 386 | SCReturnInt(-1); |
93 | 386 | } |
94 | 716 | if (keylen / 2 > UINT8_MAX) { |
95 | 201 | SCLogError("Key length too big for XOR transform"); |
96 | 201 | DetectTransformXorFree(de_ctx, pxd); |
97 | 201 | SCReturnInt(-1); |
98 | 201 | } |
99 | 515 | pxd->length = (uint8_t)(keylen / 2); |
100 | 515 | pxd->key = SCMalloc(keylen / 2); |
101 | 515 | if (pxd->key == NULL) { |
102 | 0 | SCLogError("memory allocation failed"); |
103 | 0 | DetectTransformXorFree(de_ctx, pxd); |
104 | 0 | SCReturnInt(-1); |
105 | 0 | } |
106 | 1.43k | for (size_t i = 0; i < keylen / 2; i++) { |
107 | 1.36k | if ((isxdigit(optstr[2 * i])) && (isxdigit(optstr[2 * i + 1]))) { |
108 | 916 | pxd->key[i] = (uint8_t)((optstr[2 * i] >= 'A' ? ((optstr[2 * i] & 0xdf) - 'A') + 10 |
109 | 916 | : (optstr[2 * i] - '0')) |
110 | 916 | << 4); |
111 | 916 | pxd->key[i] |= (optstr[2 * i + 1] >= 'A' ? ((optstr[2 * i + 1] & 0xdf) - 'A') + 10 |
112 | 916 | : (optstr[2 * i + 1] - '0')); |
113 | 916 | } else { |
114 | 448 | SCLogError("XOR transform key must be hexadecimal characters only"); |
115 | 448 | DetectTransformXorFree(de_ctx, pxd); |
116 | 448 | SCReturnInt(-1); |
117 | 448 | } |
118 | 1.36k | } |
119 | | |
120 | 67 | int r = DetectSignatureAddTransform(s, DETECT_TRANSFORM_XOR, pxd); |
121 | 67 | if (r != 0) { |
122 | 14 | DetectTransformXorFree(de_ctx, pxd); |
123 | 14 | } |
124 | | |
125 | 67 | SCReturnInt(r); |
126 | 515 | } |
127 | | |
128 | | static void DetectTransformXor(InspectionBuffer *buffer, void *options) |
129 | 0 | { |
130 | 0 | const uint8_t *input = buffer->inspect; |
131 | 0 | const uint32_t input_len = buffer->inspect_len; |
132 | 0 | DetectTransformXorData *pxd = options; |
133 | 0 | if (input_len == 0) { |
134 | 0 | return; |
135 | 0 | } |
136 | 0 | uint8_t *output = InspectionBufferCheckAndExpand(buffer, input_len); |
137 | 0 | if (output == NULL) { |
138 | 0 | return; |
139 | 0 | } |
140 | | |
141 | 0 | for (uint32_t i = 0; i < input_len; i++) { |
142 | 0 | output[i] = input[i] ^ pxd->key[i % pxd->length]; |
143 | 0 | } |
144 | 0 | InspectionBufferTruncate(buffer, input_len); |
145 | 0 | } |
146 | | |
147 | | #ifdef UNITTESTS |
148 | | #include "tests/detect-transform-xor.c" |
149 | | #endif |