From: Philippe Antoine Date: Wed, 30 Oct 2024 12:54:03 +0000 (+0100) Subject: transforms: move xor to rust X-Git-Tag: suricata-8.0.0-beta1~728 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8984bc680112f31acb9d0289a299d63c9dd9caf6;p=thirdparty%2Fsuricata.git transforms: move xor to rust Ticket: 7229 --- diff --git a/rust/Cargo.toml.in b/rust/Cargo.toml.in index a1b53e3b58..f99ac2728d 100644 --- a/rust/Cargo.toml.in +++ b/rust/Cargo.toml.in @@ -62,6 +62,7 @@ base64 = "~0.22.1" bendy = { version = "~0.3.3", default-features = false } asn1-rs = { version = "~0.6.1" } ldap-parser = { version = "~0.4.0" } +hex = "~0.4.3" time = "~0.3.36" @@ -71,4 +72,3 @@ suricata-lua-sys = { version = "0.1.0-alpha.3" } [dev-dependencies] test-case = "~3.3.1" -hex = "~0.4.3" diff --git a/rust/src/detect/mod.rs b/rust/src/detect/mod.rs index 276094eb3f..1857c22ee2 100644 --- a/rust/src/detect/mod.rs +++ b/rust/src/detect/mod.rs @@ -76,6 +76,7 @@ pub struct SCSigTableElmt { } pub(crate) const SIGMATCH_NOOPT: u16 = 1; // BIT_U16(0) in detect.h +pub(crate) const SIGMATCH_QUOTES_MANDATORY: u16 = 0x40; // BIT_U16(6) in detect.h pub(crate) const SIGMATCH_INFO_STICKY_BUFFER: u16 = 0x200; // BIT_U16(9) /// cbindgen:ignore diff --git a/rust/src/detect/transforms/mod.rs b/rust/src/detect/transforms/mod.rs index 6e31de80fc..a8fc98234b 100644 --- a/rust/src/detect/transforms/mod.rs +++ b/rust/src/detect/transforms/mod.rs @@ -25,6 +25,7 @@ pub mod dotprefix; pub mod hash; pub mod http_headers; pub mod strip_whitespace; +pub mod xor; #[repr(C)] #[allow(non_snake_case)] diff --git a/rust/src/detect/transforms/xor.rs b/rust/src/detect/transforms/xor.rs new file mode 100644 index 0000000000..cf801170d9 --- /dev/null +++ b/rust/src/detect/transforms/xor.rs @@ -0,0 +1,148 @@ +/* Copyright (C) 2024 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. + */ + +use super::{ + DetectHelperTransformRegister, DetectSignatureAddTransform, InspectionBufferCheckAndExpand, + InspectionBufferLength, InspectionBufferPtr, InspectionBufferTruncate, SCTransformTableElmt, +}; +use crate::detect::SIGMATCH_QUOTES_MANDATORY; + +use std::ffi::CStr; +use std::os::raw::{c_int, c_void}; + +static mut G_TRANSFORM_XOR_ID: c_int = 0; + +#[derive(Debug, PartialEq)] +struct DetectTransformXorData { + key: Vec, +} + +fn xor_parse_do(i: &str) -> Option { + if i.len() % 2 != 0 { + SCLogError!("XOR transform key's length must be an even number"); + return None; + } + if i.len() / 2 > u8::MAX.into() { + SCLogError!("Key length too big for XOR transform"); + return None; + } + if let Ok(key) = hex::decode(i) { + return Some(DetectTransformXorData { key }); + } + SCLogError!("XOR transform key must be hexadecimal characters only"); + return None; +} + +unsafe fn xor_parse(raw: *const std::os::raw::c_char) -> *mut c_void { + let raw: &CStr = CStr::from_ptr(raw); //unsafe + if let Ok(s) = raw.to_str() { + if let Some(ctx) = xor_parse_do(s) { + let boxed = Box::new(ctx); + return Box::into_raw(boxed) as *mut _; + } + } + return std::ptr::null_mut(); +} + +#[no_mangle] +unsafe extern "C" fn xor_setup( + _de: *mut c_void, s: *mut c_void, opt_str: *const std::os::raw::c_char, +) -> c_int { + let ctx = xor_parse(opt_str); + if ctx.is_null() { + return -1; + } + return DetectSignatureAddTransform(s, G_TRANSFORM_XOR_ID, ctx); +} + +fn xor_transform_do(input: &[u8], output: &mut [u8], ctx: &DetectTransformXorData) { + let mut ki = 0; + for (i, o) in input.iter().zip(output.iter_mut()) { + *o = (*i) ^ ctx.key[ki]; + ki = (ki + 1) % ctx.key.len(); + } +} + +#[no_mangle] +unsafe extern "C" fn xor_transform(buffer: *mut c_void, ctx: *mut c_void) { + let input = InspectionBufferPtr(buffer); + let input_len = InspectionBufferLength(buffer); + if input.is_null() || input_len == 0 { + return; + } + let input = build_slice!(input, input_len as usize); + + let output = InspectionBufferCheckAndExpand(buffer, input_len); + if output.is_null() { + // allocation failure + return; + } + let output = std::slice::from_raw_parts_mut(output, input_len as usize); + + let ctx = cast_pointer!(ctx, DetectTransformXorData); + xor_transform_do(input, output, ctx); + + InspectionBufferTruncate(buffer, input_len); +} + +unsafe extern "C" fn xor_free(_de: *mut c_void, ctx: *mut c_void) { + std::mem::drop(Box::from_raw(ctx as *mut DetectTransformXorData)); +} + +#[no_mangle] +pub unsafe extern "C" fn DetectTransformXorRegister() { + let kw = SCTransformTableElmt { + name: b"xor\0".as_ptr() as *const libc::c_char, + desc: b"modify buffer via XOR decoding before inspection\0".as_ptr() as *const libc::c_char, + url: b"/rules/transforms.html#xor\0".as_ptr() as *const libc::c_char, + Setup: xor_setup, + flags: SIGMATCH_QUOTES_MANDATORY, + Transform: xor_transform, + Free: Some(xor_free), + TransformValidate: None, + }; + unsafe { + G_TRANSFORM_XOR_ID = DetectHelperTransformRegister(&kw); + if G_TRANSFORM_XOR_ID < 0 { + SCLogWarning!("Failed registering transform dot_prefix"); + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_xor_parse() { + assert!(xor_parse_do("nohexa").is_none()); + let key = b"\x0a\x0d\xc8\xff"; + assert_eq!( + xor_parse_do("0a0DC8ff"), + Some(DetectTransformXorData { key: key.to_vec() }) + ); + } + + #[test] + fn test_xor_transform() { + let buf = b"example.com"; + let mut out = vec![0; buf.len()]; + let ctx = xor_parse_do("0a0DC8ff").unwrap(); + xor_transform_do(buf, &mut out, &ctx); + assert_eq!(out, b"ou\xa9\x92za\xad\xd1ib\xa5"); + } +} diff --git a/src/Makefile.am b/src/Makefile.am index 353a486bf0..d0311e20d9 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -308,7 +308,6 @@ noinst_HEADERS = \ detect-transform-base64.h \ detect-transform-pcrexform.h \ detect-transform-urldecode.h \ - detect-transform-xor.h \ detect-ttl.h \ detect-udphdr.h \ detect-uricontent.h \ @@ -868,7 +867,6 @@ libsuricata_c_a_SOURCES = \ detect-transform-base64.c \ detect-transform-pcrexform.c \ detect-transform-urldecode.c \ - detect-transform-xor.c \ detect-ttl.c \ detect-udphdr.c \ detect-uricontent.c \ @@ -1133,7 +1131,6 @@ EXTRA_DIST = \ tests/detect-icmpv6hdr.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 3d5ba9eaf5..cd6001ed54 100644 --- a/src/detect-engine-register.c +++ b/src/detect-engine-register.c @@ -217,7 +217,6 @@ #include "detect-transform-pcrexform.h" #include "detect-transform-urldecode.h" -#include "detect-transform-xor.h" #include "detect-transform-base64.h" #include "util-rule-vars.h" diff --git a/src/detect-transform-xor.c b/src/detect-transform-xor.c deleted file mode 100644 index e42700feb3..0000000000 --- a/src/detect-transform-xor.c +++ /dev/null @@ -1,146 +0,0 @@ -/* 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("memory allocation failed"); - SCReturnInt(-1); - } - - size_t keylen = strlen(optstr); - if (keylen % 2 == 1) { - SCLogError("XOR transform key's length must be an even number"); - DetectTransformXorFree(de_ctx, pxd); - SCReturnInt(-1); - } - if (keylen / 2 > UINT8_MAX) { - SCLogError("Key length too big for XOR transform"); - DetectTransformXorFree(de_ctx, pxd); - SCReturnInt(-1); - } - pxd->length = (uint8_t)(keylen / 2); - pxd->key = SCMalloc(keylen / 2); - if (pxd->key == NULL) { - SCLogError("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] = (uint8_t)((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("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; - if (input_len == 0) { - return; - } - 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 deleted file mode 100644 index 3ac2e344df..0000000000 --- a/src/detect-transform-xor.h +++ /dev/null @@ -1,30 +0,0 @@ -/* 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 SURICATA_DETECT_TRANSFORM_XOR_H -#define SURICATA_DETECT_TRANSFORM_XOR_H - -/* prototypes */ -void DetectTransformXorRegister(void); - -#endif /* SURICATA_DETECT_TRANSFORM_XOR_H */ diff --git a/src/tests/detect-transform-xor.c b/src/tests/detect-transform-xor.c deleted file mode 100644 index 3a73665e76..0000000000 --- a/src/tests/detect-transform-xor.c +++ /dev/null @@ -1,67 +0,0 @@ -/* 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); -}