Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/userguide/lua/libs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ environment without access to additional modules.
packetlib
rule
ssh
ja3
90 changes: 90 additions & 0 deletions doc/userguide/lua/libs/ja3.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
JA3
---

JA3 details are exposes to Lua scripts with the
``suricata.ja3`` library, For example::

local ja3 = require("suricata.ja3")

If you want to use ja3, you can either set suricata.yaml option
``app-layer.protocols.tls.ja3-fingerprints`` to true,
or specify it in the ``init`` function of your lua script
by calling ``ja3.enable_ja3()``::

function init (args)
ja3.enable_ja3()
return {}
end

``ja3.enable_ja3()`` will not enable ja3 if they are explicitly
disabled, so you should add ``requires: feature ja3;`` to your rule.

For use in rule matching, the rule may **hook** into a TLS or QUIC
transaction state if you want to match on only one of these protocols.
Or you should use need ``ja3`` or ``ja3s`` in your init script::

function init (args)
ja3.enable_ja3()
local needs = {}
needs["ja3s"] = true
return needs
end

Transaction
~~~~~~~~~~~

JA3 is transaction based, and the current transaction must be obtained before use::

local tx, err = ja3.get_tx()
if tx == err then
print(err)
end

All other functions are methods on the transaction (either a QUIC or a TLS one).

Transaction Methods
~~~~~~~~~~~~~~~~~~~

``ja3_get_hash()``
^^^^^^^^^^^^^^^^^^

Get the ja3 value as a hash.

Example::

local tx = ja3.get_tx()
local h = tx:ja3_get_hash();
print (h)

``ja3_get_string()``
^^^^^^^^^^^^^^^^^^^^

Get the ja3 value as a string.

Example::

local tx = ja3.get_tx()
local s = tx:ja3_get_string();
print (s)

``ja3s_get_hash()``
^^^^^^^^^^^^^^^^^^^

Get the ja3s value as a hash.

Example::

local tx = ja3.get_tx()
local h = tx:ja3s_get_hash();
print (h)

``ja3s_get_string()``
^^^^^^^^^^^^^^^^^^^^^

Get the ja3s value as a string.

Example::

local tx = ja3.get_tx()
local s = tx:ja3s_get_string();
print (s)
120 changes: 0 additions & 120 deletions doc/userguide/lua/lua-functions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -348,126 +348,6 @@ Example:
end
end


JA3
---

JA3 must be enabled in the Suricata config file (set 'app-layer.protocols.tls.ja3-fingerprints' to 'yes').

For log output, initialize with:

::

function init (args)
local needs = {}
needs["protocol"] = "tls"
return needs
end

For detection, initialization is as follows:

::

function init (args)
local needs = {}
needs["tls"] = tostring(true)
return needs
end

Ja3GetHash
~~~~~~~~~~

Get the JA3 hash (md5sum of JA3 string) through Ja3GetHash.

Example:

::

function log (args)
hash = Ja3GetHash()
if hash == nil then
return
end
end

Ja3GetString
~~~~~~~~~~~~

Get the JA3 string through Ja3GetString.

Example:

::

function log (args)
str = Ja3GetString()
if str == nil then
return
end
end

Ja3SGetHash
~~~~~~~~~~~

Get the JA3S hash (md5sum of JA3S string) through JA3SGetHash.

Examples:

::

function log (args)
hash = Ja3SGetHash()
if hash == nil then
return
end
end

Or, for detection:

::

function match (args)
hash = Ja3SGetHash()
if hash == nil then
return 0
end

// matching code

return 0
end

JA3SGetString
~~~~~~~~~~~~~

Get the JA3S string through Ja3SGetString.

Examples:

::

function log (args)
str = Ja3SGetString()
if str == nil then
return
end
end

Or, for detection:

::

function match (args)
str = Ja3SGetString()
if str == nil then
return 0
end

// matching code

return 0
end

Files
-----

Expand Down
20 changes: 12 additions & 8 deletions rust/src/quic/detect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* 02110-1301, USA.
*/

use crate::core::DetectEngineThreadCtx;
use crate::core::{DetectEngineThreadCtx, STREAM_TOCLIENT, STREAM_TOSERVER};
use crate::quic::quic::QuicTransaction;
use std::os::raw::c_void;
use std::ptr;
Expand Down Expand Up @@ -52,17 +52,21 @@ pub unsafe extern "C" fn SCQuicTxGetSni(

#[no_mangle]
pub unsafe extern "C" fn SCQuicTxGetJa3(
tx: &QuicTransaction, buffer: *mut *const u8, buffer_len: *mut u32,
) -> u8 {
tx: &QuicTransaction, dir: u8, buffer: *mut *const u8, buffer_len: *mut u32,
) -> bool {
if tx.client {
if dir & STREAM_TOSERVER == 0 {
return false;
}
} else if dir & STREAM_TOCLIENT == 0 {
return false;
}
if let Some(ja3) = &tx.ja3 {
*buffer = ja3.as_ptr();
*buffer_len = ja3.len() as u32;
1
} else {
*buffer = ptr::null();
*buffer_len = 0;
0
return true;
}
return false;
}

#[no_mangle]
Expand Down
6 changes: 5 additions & 1 deletion src/datasets.c
Original file line number Diff line number Diff line change
Expand Up @@ -1370,7 +1370,11 @@ static int DatasetOpSerialized(Dataset *set, const char *string, DatasetOpFunc D

switch (set->type) {
case DATASET_TYPE_STRING: {
uint32_t decoded_size = SCBase64DecodeBufferSize(strlen(string));
if (strlen(string) > UINT16_MAX) {
// size check before cast and stack allocation
return -1;
}
uint32_t decoded_size = SCBase64DecodeBufferSize((uint32_t)strlen(string));
uint8_t decoded[decoded_size];
uint32_t num_decoded = SCBase64Decode(
(const uint8_t *)string, strlen(string), SCBase64ModeStrict, decoded);
Expand Down
25 changes: 14 additions & 11 deletions src/detect-bsize.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,37 +41,38 @@
/*prototypes*/
static int DetectBsizeSetup (DetectEngineCtx *, Signature *, const char *);
static void DetectBsizeFree (DetectEngineCtx *, void *);
static int SigParseGetMaxBsize(const DetectU64Data *bsz);
static int SigParseGetMaxBsize(const DetectU64Data *bsz, uint64_t *bsize);
#ifdef UNITTESTS
static void DetectBsizeRegisterTests (void);
#endif

bool DetectBsizeValidateContentCallback(Signature *s, const SignatureInitDataBuffer *b)
{
int bsize = -1;
uint64_t bsize;
int retval = -1;
const DetectU64Data *bsz;
for (const SigMatch *sm = b->head; sm != NULL; sm = sm->next) {
if (sm->type == DETECT_BSIZE) {
bsz = (const DetectU64Data *)sm->ctx;
bsize = SigParseGetMaxBsize(bsz);
retval = SigParseGetMaxBsize(bsz, &bsize);
break;
}
}

if (bsize == -1) {
if (retval == -1) {
return true;
}

uint64_t needed;
if (bsize >= 0) {
if (retval == 0) {
int len, offset;
SigParseRequiredContentSize(s, bsize, b->head, &len, &offset);
SCLogDebug("bsize: %d; len: %d; offset: %d [%s]", bsize, len, offset, s->sig_str);
SCLogDebug("bsize: %" PRIu64 "; len: %d; offset: %d [%s]", bsize, len, offset, s->sig_str);
needed = len;
if (len > bsize) {
if ((uint64_t)len > bsize) {
goto value_error;
}
if ((len + offset) > bsize) {
if ((uint64_t)(len + offset) > bsize) {
needed += offset;
goto value_error;
}
Expand Down Expand Up @@ -159,14 +160,16 @@ int DetectBsizeMatch(const SigMatchCtx *ctx, const uint64_t buffer_size, bool eo
return 0;
}

static int SigParseGetMaxBsize(const DetectU64Data *bsz)
static int SigParseGetMaxBsize(const DetectU64Data *bsz, uint64_t *bsize)
{
switch (bsz->mode) {
case DETECT_UINT_LT:
case DETECT_UINT_EQ:
return bsz->arg1;
*bsize = bsz->arg1;
SCReturnInt(0);
case DETECT_UINT_RA:
return bsz->arg2;
*bsize = bsz->arg2;
SCReturnInt(0);
case DETECT_UINT_GT:
default:
SCReturnInt(-2);
Expand Down
2 changes: 1 addition & 1 deletion src/detect-byte-extract.c
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ int DetectByteExtractDoMatch(DetectEngineThreadCtx *det_ctx, const SigMatchData

ptr += extbytes;

det_ctx->buffer_offset = ptr - payload;
det_ctx->buffer_offset = (uint32_t)(ptr - payload);

*value = val;
SCLogDebug("extracted value is %"PRIu64, val);
Expand Down
2 changes: 1 addition & 1 deletion src/detect-bytejump.c
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ bool DetectBytejumpDoMatch(DetectEngineThreadCtx *det_ctx, const Signature *s,

/* Adjust the detection context to the jump location. */
DEBUG_VALIDATE_BUG_ON(jumpptr < payload);
det_ctx->buffer_offset = jumpptr - payload;
det_ctx->buffer_offset = (uint32_t)(jumpptr - payload);

SCReturnBool(true);
}
Expand Down
2 changes: 1 addition & 1 deletion src/detect-bytemath.c
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ int DetectByteMathDoMatch(DetectEngineThreadCtx *det_ctx, const DetectByteMathDa
break;
}

det_ctx->buffer_offset = ptr - payload;
det_ctx->buffer_offset = (uint32_t)(ptr - payload);

if (data->flags & DETECT_BYTEMATH_FLAG_BITMASK) {
val &= data->bitmask_val;
Expand Down
2 changes: 1 addition & 1 deletion src/detect-bytetest.c
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ static DetectBytetestData *DetectBytetestParse(
data->neg_op = true;
op_ptr = &args[1][1];
while (isspace((char)*op_ptr) || (*op_ptr == ',')) op_ptr++;
op_offset = op_ptr - &args[1][0];
op_offset = (uint32_t)(op_ptr - &args[1][0]);
} else {
data->neg_op = false;
}
Expand Down
Loading
Loading