From: Philippe Antoine Date: Fri, 22 Oct 2021 17:47:49 +0000 (+0200) Subject: detect: xor transform X-Git-Tag: suricata-7.0.0-beta1~1018 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0cfdec1266d76842286ca06cf0d390ca971b0c48;p=thirdparty%2Fsuricata.git detect: xor transform Ticket: 3285 The xor transform applies xor decoding to a buffer, with a key specified as an option in hexadecimal. Arbitrary key sizes are accepted. --- diff --git a/doc/userguide/rules/transforms.rst b/doc/userguide/rules/transforms.rst index 7298e76015..91ab2ef5fc 100644 --- a/doc/userguide/rules/transforms.rst +++ b/doc/userguide/rules/transforms.rst @@ -120,3 +120,17 @@ url_decode Decodes url-encoded data, ie replacing '+' with space and '%HH' with its value. This does not decode unicode '%uZZZZ' encoding + +xor +--- + +Takes the buffer, applies xor decoding. + +.. note:: this transform requires a mandatory option which is the hexadecimal encoded xor key. + + +This example alerts if ``http.uri`` contains ``password=`` xored with 4-bytes key ``0d0ac8ff`` +Example:: + + alert http any any -> any any (msg:"HTTP with xor"; http.uri; \ + xor:"0d0ac8ff"; content:"password="; sid:1;) diff --git a/src/Makefile.am b/src/Makefile.am index 76fd7a2dbf..475f0892fc 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -336,6 +336,7 @@ noinst_HEADERS = \ detect-transform-sha256.h \ detect-transform-strip-whitespace.h \ detect-transform-urldecode.h \ + detect-transform-xor.h \ detect-ttl.h \ detect-udphdr.h \ detect-uricontent.h \ @@ -920,6 +921,7 @@ libsuricata_c_a_SOURCES = \ detect-transform-sha256.c \ detect-transform-strip-whitespace.c \ detect-transform-urldecode.c \ + detect-transform-xor.c \ detect-ttl.c \ detect-udphdr.c \ detect-uricontent.c \ @@ -1191,6 +1193,7 @@ EXTRA_DIST = \ tests/detect-tcpmss.c \ tests/detect-template.c \ tests/detect-transform-pcrexform.c \ + tests/detect-transform-xor.c \ tests/detect-ttl.c \ tests/source-pcap.c \ tests/app-layer-htp-file.c \ diff --git a/src/detect-engine-register.c b/src/detect-engine-register.c index 2acf6f21e7..c043566749 100644 --- a/src/detect-engine-register.c +++ b/src/detect-engine-register.c @@ -231,6 +231,7 @@ #include "detect-transform-dotprefix.h" #include "detect-transform-pcrexform.h" #include "detect-transform-urldecode.h" +#include "detect-transform-xor.h" #include "util-rule-vars.h" @@ -659,6 +660,7 @@ void SigTableSetup(void) DetectTransformDotPrefixRegister(); DetectTransformPcrexformRegister(); DetectTransformUrlDecodeRegister(); + DetectTransformXorRegister(); /* close keyword registration */ DetectBufferTypeCloseRegistration(); diff --git a/src/detect-engine-register.h b/src/detect-engine-register.h index aea0e60f89..a805d4ba29 100644 --- a/src/detect-engine-register.h +++ b/src/detect-engine-register.h @@ -300,6 +300,7 @@ enum DetectKeywordId { DETECT_TRANSFORM_DOTPREFIX, DETECT_TRANSFORM_PCREXFORM, DETECT_TRANSFORM_URL_DECODE, + DETECT_TRANSFORM_XOR, DETECT_AL_IKE_EXCH_TYPE, DETECT_AL_IKE_SPI_INITIATOR, diff --git a/src/detect-transform-xor.c b/src/detect-transform-xor.c new file mode 100644 index 0000000000..7fbae5239b --- /dev/null +++ b/src/detect-transform-xor.c @@ -0,0 +1,144 @@ +/* Copyright (C) 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 + * + * \author Philippe Antoine + * + * Implements the xor transform keyword with option support + */ + +#include "suricata-common.h" +#include "detect.h" +#include "detect-engine.h" +#include "detect-parse.h" +#include "detect-transform-xor.h" + +typedef struct DetectTransformXorData { + uint8_t *key; + // limit the key length + uint8_t length; +} DetectTransformXorData; + +static int DetectTransformXorSetup(DetectEngineCtx *, Signature *, const char *); +static void DetectTransformXorFree(DetectEngineCtx *, void *); +static void DetectTransformXor(InspectionBuffer *buffer, void *options); +#ifdef UNITTESTS +void DetectTransformXorRegisterTests(void); +#endif + +void DetectTransformXorRegister(void) +{ + sigmatch_table[DETECT_TRANSFORM_XOR].name = "xor"; + sigmatch_table[DETECT_TRANSFORM_XOR].desc = "modify buffer via XOR decoding before inspection"; + sigmatch_table[DETECT_TRANSFORM_XOR].url = "/rules/transforms.html#xor"; + sigmatch_table[DETECT_TRANSFORM_XOR].Transform = DetectTransformXor; + sigmatch_table[DETECT_TRANSFORM_XOR].Free = DetectTransformXorFree; + sigmatch_table[DETECT_TRANSFORM_XOR].Setup = DetectTransformXorSetup; +#ifdef UNITTESTS + sigmatch_table[DETECT_TRANSFORM_XOR].RegisterTests = DetectTransformXorRegisterTests; +#endif + sigmatch_table[DETECT_TRANSFORM_XOR].flags |= SIGMATCH_QUOTES_MANDATORY; +} + +static void DetectTransformXorFree(DetectEngineCtx *de_ctx, void *ptr) +{ + if (ptr != NULL) { + DetectTransformXorData *pxd = (DetectTransformXorData *)ptr; + SCFree(pxd->key); + SCFree(pxd); + } +} + +/** + * \internal + * \brief Apply the xor keyword to the last pattern match + * \param det_ctx detection engine ctx + * \param s signature + * \param optstr options string + * \retval 0 ok + * \retval -1 failure + */ +static int DetectTransformXorSetup(DetectEngineCtx *de_ctx, Signature *s, const char *optstr) +{ + SCEnter(); + + // Create pxd from optstr + DetectTransformXorData *pxd = SCCalloc(1, sizeof(*pxd)); + if (pxd == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "memory allocation failed"); + SCReturnInt(-1); + } + + size_t keylen = strlen(optstr); + if (keylen % 2 == 1) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "XOR transform key's length must be an even number"); + DetectTransformXorFree(de_ctx, pxd); + SCReturnInt(-1); + } + if (keylen / 2 > UINT8_MAX) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "Key length too big for XOR transform"); + DetectTransformXorFree(de_ctx, pxd); + SCReturnInt(-1); + } + pxd->length = keylen / 2; + pxd->key = SCMalloc(keylen / 2); + if (pxd->key == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "memory allocation failed"); + DetectTransformXorFree(de_ctx, pxd); + SCReturnInt(-1); + } + for (size_t i = 0; i < keylen / 2; i++) { + if ((isxdigit(optstr[2 * i])) && (isxdigit(optstr[2 * i + 1]))) { + pxd->key[i] = (optstr[2 * i] >= 'A' ? ((optstr[2 * i] & 0xdf) - 'A') + 10 + : (optstr[2 * i] - '0')) + << 4; + pxd->key[i] |= (optstr[2 * i + 1] >= 'A' ? ((optstr[2 * i + 1] & 0xdf) - 'A') + 10 + : (optstr[2 * i + 1] - '0')); + } else { + SCLogError(SC_ERR_INVALID_SIGNATURE, + "XOR transform key must be hexadecimal characters only"); + DetectTransformXorFree(de_ctx, pxd); + SCReturnInt(-1); + } + } + + int r = DetectSignatureAddTransform(s, DETECT_TRANSFORM_XOR, pxd); + if (r != 0) { + DetectTransformXorFree(de_ctx, pxd); + } + + SCReturnInt(r); +} + +static void DetectTransformXor(InspectionBuffer *buffer, void *options) +{ + const uint8_t *input = buffer->inspect; + const uint32_t input_len = buffer->inspect_len; + DetectTransformXorData *pxd = options; + uint8_t output[input_len]; + + for (uint32_t i = 0; i < input_len; i++) { + output[i] = input[i] ^ pxd->key[i % pxd->length]; + } + InspectionBufferCopy(buffer, output, input_len); +} + +#ifdef UNITTESTS +#include "tests/detect-transform-xor.c" +#endif diff --git a/src/detect-transform-xor.h b/src/detect-transform-xor.h new file mode 100644 index 0000000000..0c585167f9 --- /dev/null +++ b/src/detect-transform-xor.h @@ -0,0 +1,30 @@ +/* Copyright (C) 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 + * + * \author Philippe Antoine + */ + +#ifndef __DETECT_TRANSFORM_XOR_H__ +#define __DETECT_TRANSFORM_XOR_H__ + +/* prototypes */ +void DetectTransformXorRegister(void); + +#endif /* __DETECT_TRANSFORM_XOR_H__ */ diff --git a/src/tests/detect-transform-xor.c b/src/tests/detect-transform-xor.c new file mode 100644 index 0000000000..3a73665e76 --- /dev/null +++ b/src/tests/detect-transform-xor.c @@ -0,0 +1,67 @@ +/* Copyright (C) 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. + */ + +#include "../suricata-common.h" + +#include "../detect-engine.h" + +#include "../detect-transform-xor.h" + +#include "../util-unittest.h" + +/** + * \test signature with an invalid xor value. + */ + +static int DetectTransformXorParseTest01(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + Signature *sig = DetectEngineAppendSig(de_ctx, "alert tcp any any <> any 1 xor:\"nohexa\";"); + FAIL_IF_NOT_NULL(sig); + + DetectEngineCtxFree(de_ctx); + PASS; +} + +/** + * \test signature with a valid xor value. + */ + +static int DetectTransformXorParseTest02(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + Signature *sig = DetectEngineAppendSig(de_ctx, + "alert http any any -> any any (msg:\"HTTP with xor\"; http.request_line; " + "xor:\"0a0DC8ff\"; content:\"/z4d4kWk.jpg\"; sid:1;)"); + FAIL_IF_NULL(sig); + + DetectEngineCtxFree(de_ctx); + PASS; +} + +/** + * \brief this function registers unit tests for DetectTransformXor + */ +void DetectTransformXorRegisterTests(void) +{ + UtRegisterTest("DetectTransformXorParseTest01", DetectTransformXorParseTest01); + UtRegisterTest("DetectTransformXorParseTest02", DetectTransformXorParseTest02); +}