detect/transforms: add zlib_deflate transform

Ticket: 7846
pull/14827/head
Philippe Antoine 3 months ago committed by Victor Julien
parent dbea660729
commit 539e4ee665

@ -415,3 +415,24 @@ Example::
from_base64: offset 13 ;
gunzip; content:"This is compressed then base64-encoded"; startswith; endswith;
sid:2; rev:1;)
zlib_deflate
------------
Takes the buffer, applies zlib decompression.
This transform takes an optional argument which is a comma-separated list of key-values.
The only key being interperted is ``max-size``, which is the max output size.
Default for max-size is 1024.
If the decompressed data were to be larger than max-size,
the transform will decompress data up to max-size.
Value 0 is forbidden for max-size (there is no unlimited value).
This example alerts if ``http.uri`` contains base64-encoded zlib-compressed value
Example::
alert http any any -> any any (msg:"from_base64 + gunzip";
http.uri; content:"/zb64?value="; fast_pattern;
from_base64: offset 12 ;
zlib_deflate; content:"This is compressed then base64-encoded"; startswith; endswith;
sid:2; rev:1;)

@ -17,7 +17,7 @@
use crate::detect::uint::detect_parse_uint_with_unit;
use crate::detect::SIGMATCH_OPTIONAL_OPT;
use flate2::bufread::GzDecoder;
use flate2::bufread::{GzDecoder, ZlibDecoder};
use suricata_sys::sys::{
DetectEngineCtx, DetectEngineThreadCtx, InspectionBuffer, SCDetectHelperTransformRegister,
SCDetectSignatureAddTransform, SCInspectionBufferCheckAndExpand, SCInspectionBufferTruncate,
@ -29,6 +29,7 @@ use std::io::Read;
use std::os::raw::{c_int, c_void};
static mut G_TRANSFORM_GUNZIP_ID: c_int = 0;
static mut G_TRANSFORM_ZLIB_DEFLATE_ID: c_int = 0;
#[derive(Debug, PartialEq)]
struct DetectTransformDecompressData {
@ -37,7 +38,7 @@ struct DetectTransformDecompressData {
const DEFAULT_MAX_SIZE: u32 = 1024;
// 16 MiB
const ABSOLUTE_MAX_SIZE: u32 = 16*1024*1024;
const ABSOLUTE_MAX_SIZE: u32 = 16 * 1024 * 1024;
fn decompress_parse_do(s: &str) -> Option<DetectTransformDecompressData> {
let mut max_size_parsed = None;
@ -121,8 +122,10 @@ fn gunzip_transform_do(input: &[u8], output: &mut [u8]) -> Option<u32> {
};
}
unsafe extern "C" fn gunzip_transform(
_det: *mut DetectEngineThreadCtx, buffer: *mut InspectionBuffer, ctx: *mut c_void,
pub type DecompressFn = fn(input: &[u8], output: &mut [u8]) -> Option<u32>;
unsafe fn decompress_transform(
buffer: *mut InspectionBuffer, ctx: &DetectTransformDecompressData, decompress_fn: DecompressFn,
) {
let input = (*buffer).inspect;
let input_len = (*buffer).inspect_len;
@ -130,8 +133,6 @@ unsafe extern "C" fn gunzip_transform(
return;
}
let input = build_slice!(input, input_len as usize);
let ctx = cast_pointer!(ctx, DetectTransformDecompressData);
let output = SCInspectionBufferCheckAndExpand(buffer, ctx.max_size);
if output.is_null() {
// allocation failure
@ -150,7 +151,7 @@ unsafe extern "C" fn gunzip_transform(
};
// this succeeds if decompressed data > max_size, but we get nb = max_size
if let Some(nb) = gunzip_transform_do(input, buf) {
if let Some(nb) = decompress_fn(input, buf) {
SCInspectionBufferTruncate(buffer, nb);
} else {
// decompression failure
@ -158,6 +159,13 @@ unsafe extern "C" fn gunzip_transform(
}
}
unsafe extern "C" fn gunzip_transform(
_det: *mut DetectEngineThreadCtx, buffer: *mut InspectionBuffer, ctx: *mut c_void,
) {
let ctx = cast_pointer!(ctx, DetectTransformDecompressData);
decompress_transform(buffer, ctx, gunzip_transform_do);
}
unsafe extern "C" fn decompress_free(_de: *mut DetectEngineCtx, ctx: *mut c_void) {
std::mem::drop(Box::from_raw(ctx as *mut DetectTransformDecompressData));
}
@ -171,6 +179,35 @@ unsafe extern "C" fn decompress_id(data: *mut *const u8, length: *mut u32, ctx:
*length = std::mem::size_of::<DetectTransformDecompressData>() as u32; // 4
}
unsafe extern "C" fn zlib_deflate_setup(
de: *mut DetectEngineCtx, s: *mut Signature, opt_str: *const std::os::raw::c_char,
) -> c_int {
let ctx = decompress_parse(opt_str);
if ctx.is_null() {
return -1;
}
let r = SCDetectSignatureAddTransform(s, G_TRANSFORM_ZLIB_DEFLATE_ID, ctx);
if r != 0 {
decompress_free(de, ctx);
}
return r;
}
fn zlib_deflate_transform_do(input: &[u8], output: &mut [u8]) -> Option<u32> {
let mut gz = ZlibDecoder::new(input);
return match gz.read(output) {
Ok(n) => Some(n as u32),
_ => None,
};
}
unsafe extern "C" fn zlib_deflate_transform(
_det: *mut DetectEngineThreadCtx, buffer: *mut InspectionBuffer, ctx: *mut c_void,
) {
let ctx = cast_pointer!(ctx, DetectTransformDecompressData);
decompress_transform(buffer, ctx, zlib_deflate_transform_do);
}
#[no_mangle]
pub unsafe extern "C" fn DetectTransformGunzipRegister() {
let kw = SCTransformTableElmt {
@ -192,6 +229,27 @@ pub unsafe extern "C" fn DetectTransformGunzipRegister() {
}
}
#[no_mangle]
pub unsafe extern "C" fn DetectTransformZlibDeflateRegister() {
let kw = SCTransformTableElmt {
name: b"zlib_deflate\0".as_ptr() as *const libc::c_char,
desc: b"modify buffer via zlib decompression\0".as_ptr() as *const libc::c_char,
url: b"/rules/transforms.html#zlib_deflate\0".as_ptr() as *const libc::c_char,
Setup: Some(zlib_deflate_setup),
flags: SIGMATCH_OPTIONAL_OPT,
Transform: Some(zlib_deflate_transform),
Free: Some(decompress_free),
TransformValidate: None,
TransformId: Some(decompress_id),
};
unsafe {
G_TRANSFORM_ZLIB_DEFLATE_ID = SCDetectHelperTransformRegister(&kw);
if G_TRANSFORM_ZLIB_DEFLATE_ID < 0 {
SCLogWarning!("Failed registering transform zlib_deflate");
}
}
}
#[cfg(test)]
mod tests {
use super::*;

@ -750,6 +750,7 @@ void SigTableSetup(void)
SCDetectTransformDomainRegister();
DetectTransformLuaxformRegister();
DetectTransformGunzipRegister();
DetectTransformZlibDeflateRegister();
DetectFileHandlerRegister();

Loading…
Cancel
Save