detect/pcre: add extraction for alert

With datajson infrastructure in place, it is now possible to
add data in the extra information section. Following an idea
by Jason Ish, this patch adds the feature for pcre extraction.

A PCRE such as pcre:"/(?P<alert_ua>[a-zA-Z]+)\//" will add the
content of the captured group to alert.extra.ua.
pull/13432/head
Eric Leblond 1 year ago committed by Victor Julien
parent dd94dc6cc6
commit 3fbc718728

@ -1,4 +1,4 @@
/* Copyright (C) 2007-2022 Open Information Security Foundation
/* Copyright (C) 2007-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
@ -155,6 +155,46 @@ void DetectPcreRegister (void)
#endif
}
static void DetectAlertStoreMatch(DetectEngineThreadCtx *det_ctx, const Signature *s, uint32_t idx,
uint8_t *str_ptr, uint16_t capture_len)
{
/* We need the key */
const char *json_key = VarNameStoreLookupById(idx, VAR_TYPE_ALERT_VAR);
if (json_key == NULL) {
SCFree(str_ptr);
return;
}
SCLogDebug("json key: %s", json_key);
/* Setup the data*/
if ((det_ctx->json_content_len < SIG_JSON_CONTENT_ARRAY_LEN) &&
(capture_len + strlen(json_key) + 5 < SIG_JSON_CONTENT_ITEM_LEN)) {
SCJsonBuilder *js = SCJbNewObject();
if (unlikely(js == NULL)) {
SCFree(str_ptr);
return;
}
SCJbSetStringFromBytes(js, json_key, str_ptr, capture_len);
uint32_t js_len = SCJbLen(js);
if (js_len > SIG_JSON_CONTENT_ITEM_LEN) {
SCLogDebug("Captured length is too long for JSON.");
SCFree(str_ptr);
return;
}
/* Copy js but skip the starting curly bracket to just get the inner data */
memcpy(det_ctx->json_content[det_ctx->json_content_len].json_content, SCJbPtr(js) + 1,
js_len - 1);
/* end the string as we have used memcpy */
det_ctx->json_content[det_ctx->json_content_len].json_content[js_len - 1] = 0;
det_ctx->json_content[det_ctx->json_content_len].id = (void *)s;
det_ctx->json_content_len++;
SCJbFree(js);
}
SCFree(str_ptr);
}
/**
* \brief Match a regex on a single payload.
*
@ -279,6 +319,11 @@ int DetectPcrePayloadMatch(DetectEngineThreadCtx *det_ctx, const Signature *s,
} else if (pe->captypes[x] == VAR_TYPE_FLOW_VAR && f != NULL) {
(void)DetectVarStoreMatch(det_ctx, pe->capids[x], (uint8_t *)str_ptr,
(uint16_t)capture_len, DETECT_VAR_TYPE_FLOW_POSTMATCH);
} else if (pe->captypes[x] == VAR_TYPE_ALERT_VAR) {
(void)DetectAlertStoreMatch(det_ctx, s, pe->capids[x], (uint8_t *)str_ptr,
(uint16_t)capture_len);
} else {
BUG_ON(1); // Impossible captype
SCFree(str_ptr);
@ -362,20 +407,32 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx,
int cut_capture = 0;
char *fcap = strstr(regexstr, "flow:");
char *pcap = strstr(regexstr, "pkt:");
char *acap = strstr(regexstr, "alert:");
/* take the size of the whole input as buffer size for the regex we will
* extract below. Add 1 to please Coverity's alloc_strlen test. */
size_t slen = strlen(regexstr) + 1;
if (fcap || pcap) {
if (fcap || pcap || acap) {
SCLogDebug("regexstr %s", regexstr);
if (fcap && !pcap)
bool a_set = false;
cut_capture = 0;
if (fcap) {
a_set = true;
cut_capture = (int)(fcap - regexstr);
else if (pcap && !fcap)
cut_capture = (int)(pcap - regexstr);
else {
BUG_ON(pcap == NULL); // added to assist cppcheck
BUG_ON(fcap == NULL);
cut_capture = (int)MIN((pcap - regexstr), (fcap - regexstr));
}
if (pcap) {
if (a_set)
cut_capture = (int)MIN(cut_capture, (pcap - regexstr));
else {
cut_capture = (int)(pcap - regexstr);
a_set = true;
}
}
if (acap) {
if (a_set)
cut_capture = MIN(cut_capture, (acap - regexstr));
else
cut_capture = (int)(acap - regexstr);
}
SCLogDebug("cut_capture %d", cut_capture);
@ -760,6 +817,12 @@ static int DetectPcreParseCapture(const char *regexstr, DetectEngineCtx *de_ctx,
SCLogDebug("id %u type %u", pd->capids[pd->idx], pd->captypes[pd->idx]);
pd->idx++;
} else if (strncmp(name_array[name_idx], "alert:", 6) == 0) {
pd->capids[pd->idx] =
VarNameStoreRegister(name_array[name_idx] + 6, VAR_TYPE_ALERT_VAR);
pd->captypes[pd->idx] = VAR_TYPE_ALERT_VAR;
pd->idx++;
} else {
SCLogError(" pkt/flow "
"var capture names must start with 'pkt:' or 'flow:'");
@ -825,6 +888,10 @@ static int DetectPcreParseCapture(const char *regexstr, DetectEngineCtx *de_ctx,
pd->capids[pd->idx] = VarNameStoreRegister((char *)capture_str, VAR_TYPE_FLOW_VAR);
pd->captypes[pd->idx] = VAR_TYPE_FLOW_VAR;
pd->idx++;
} else if (strcmp(type_str, "alert") == 0) {
pd->capids[pd->idx] = VarNameStoreRegister((char *)capture_str, VAR_TYPE_ALERT_VAR);
pd->captypes[pd->idx] = VAR_TYPE_ALERT_VAR;
pd->idx++;
}
//SCLogNotice("pd->capname %s", pd->capname);

@ -47,6 +47,7 @@ enum VarTypes {
VAR_TYPE_IPPAIR_VAR,
VAR_TYPE_TX_BIT,
VAR_TYPE_ALERT_VAR,
};
typedef struct GenericVar_ {

Loading…
Cancel
Save