Thank Zhihao Tao for your hard work. The document spent countless nights and weekends, using his hard work to make it convenient for everyone.
If you have any questions, please send a email to zhihao.tao@outlook.com
1. flowbits
flowbits
由两部分组成:
- 第一部分描述将要执行的动作,
- 第二部分是flowbits的名称。
有多个数据包属于一个流。Suricata
将这些流保存在内存中。flowbits
可以确保在两个不同的数据包匹配时才将生成警报。仅当两个数据包匹配时才会生成警报。
因此,当第二个数据包匹配时,Suricata
必须知道第一个数据包是否也匹配。如果数据包匹配,则flowbits
会标记流,因此当Suricata“知道”第二个数据包也匹配时,它将生成警报。
示例:
当你看第一条规则时,你会注意到如果它匹配,如果不是在规则末尾的flowbits:noalert
,它就会生成一个警报。该规则的目的是检查userlogin
上的匹配项,并在流中进行标记。因此,无需生成警报。
如果没有第一条规则,第二条规则将无效。如果第一个规则匹配,flowbits
将设置流中存在的特定条件。现在,使用第二条规则,可以检查前一个数据包是否满足第一个条件。如果此时第二条规则匹配,将生成警报。可以在规则中多次使用流位,并组合不同的功能。
void DetectFlowbitsRegister (void)
{
sigmatch_table[DETECT_FLOWBITS].name = "flowbits";
sigmatch_table[DETECT_FLOWBITS].desc = "operate on flow flag";
sigmatch_table[DETECT_FLOWBITS].url = DOC_URL DOC_VERSION "/rules/flow-keywords.html#flowbits";
sigmatch_table[DETECT_FLOWBITS].Match = DetectFlowbitMatch;
sigmatch_table[DETECT_FLOWBITS].Setup = DetectFlowbitSetup;
sigmatch_table[DETECT_FLOWBITS].Free = DetectFlowbitFree;
sigmatch_table[DETECT_FLOWBITS].RegisterTests = NULL;
/* this is compatible to ip-only signatures */
sigmatch_table[DETECT_FLOWBITS].flags |= SIGMATCH_IPONLY_COMPAT;
DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study);
}
1.1 flowbits
安装
- 解析
flowbits
具有的6种不同的动作:noalert
isset
isnotset
set
unset
toggle
int DetectFlowbitSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
{
DetectFlowbitsData *cd = NULL;
SigMatch *sm = NULL;
uint8_t fb_cmd = 0;
char fb_cmd_str[16] = "", fb_name[256] = "";
if (!DetectFlowbitParse(rawstr, fb_cmd_str, sizeof(fb_cmd_str), fb_name,
sizeof(fb_name))) {
return -1;
}
if (strcmp(fb_cmd_str,"noalert") == 0) {
fb_cmd = DETECT_FLOWBITS_CMD_NOALERT;
} else if (strcmp(fb_cmd_str,"isset") == 0) {
fb_cmd = DETECT_FLOWBITS_CMD_ISSET;
} else if (strcmp(fb_cmd_str,"isnotset") == 0) {
fb_cmd = DETECT_FLOWBITS_CMD_ISNOTSET;
} else if (strcmp(fb_cmd_str,"set") == 0) {
fb_cmd = DETECT_FLOWBITS_CMD_SET;
} else if (strcmp(fb_cmd_str,"unset") == 0) {
fb_cmd = DETECT_FLOWBITS_CMD_UNSET;
} else if (strcmp(fb_cmd_str,"toggle") == 0) {
fb_cmd = DETECT_FLOWBITS_CMD_TOGGLE;
} else {
SCLogError(SC_ERR_UNKNOWN_VALUE, "ERROR: flowbits action \"%s\" is not supported.", fb_cmd_str);
goto error;
}
- 对
noalert
设置SIG_FLAG_NOALERT
选项。
switch (fb_cmd) {
case DETECT_FLOWBITS_CMD_NOALERT:
if (strlen(fb_name) != 0)
goto error;
s->flags |= SIG_FLAG_NOALERT;
return 0;
case DETECT_FLOWBITS_CMD_ISNOTSET:
case DETECT_FLOWBITS_CMD_ISSET:
case DETECT_FLOWBITS_CMD_SET:
case DETECT_FLOWBITS_CMD_UNSET:
case DETECT_FLOWBITS_CMD_TOGGLE:
default:
if (strlen(fb_name) == 0)
goto error;
break;
}
- 分配flowbits id,并加入到签名的匹配条件中。
-
isset
和isnotset
加入DETECT_SM_LIST_MATCH
组。 -
set
、unset
及toggle
加入DETECT_SM_LIST_POSTMATCH
组。
-
...
cd = SCMalloc(sizeof(DetectFlowbitsData));
if (unlikely(cd == NULL))
goto error;
cd->idx = VarNameStoreSetupAdd(fb_name, VAR_TYPE_FLOW_BIT);
de_ctx->max_fb_id = MAX(cd->idx, de_ctx->max_fb_id);
cd->cmd = fb_cmd;
SCLogDebug("idx %" PRIu32 ", cmd %s, name %s",
cd->idx, fb_cmd_str, strlen(fb_name) ? fb_name : "(none)");
/* Okay so far so good, lets get this into a SigMatch
* and put it in the Signature. */
sm = SigMatchAlloc();
if (sm == NULL)
goto error;
sm->type = DETECT_FLOWBITS;
sm->ctx = (SigMatchCtx *)cd;
switch (fb_cmd) {
/* case DETECT_FLOWBITS_CMD_NOALERT can't happen here */
case DETECT_FLOWBITS_CMD_ISNOTSET:
case DETECT_FLOWBITS_CMD_ISSET:
/* checks, so packet list */
SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH);
break;
case DETECT_FLOWBITS_CMD_SET:
case DETECT_FLOWBITS_CMD_UNSET:
case DETECT_FLOWBITS_CMD_TOGGLE:
/* modifiers, only run when entire sig has matched */
SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_POSTMATCH);
break;
// suppress coverity warning as scan-build-7 warns w/o this.
// coverity[deadcode : FALSE]
default:
goto error;
}
return 0;
error:
if (cd != NULL)
SCFree(cd);
if (sm != NULL)
SCFree(sm);
return -1;
}
1.2 flowbits
匹配
- 如果
DETECT_SM_LIST_MATCH
有匹配项,进行注册Match函数注册。
int DetectEnginePktInspectionSetup(Signature *s)
{
...
if (s->sm_arrays[DETECT_SM_LIST_MATCH]) {
if (DetectEnginePktInspectionAppend(s, DetectEngineInspectRulePacketMatches,
NULL) < 0)
...
}
- 遍历
DETECT_SM_LIST_MATCH
中所有选项进行匹配。
static int DetectEngineInspectRulePacketMatches(
DetectEngineThreadCtx *det_ctx,
const DetectEnginePktInspectionEngine *engine,
const Signature *s,
Packet *p, uint8_t *_alert_flags)
{
...
if (sigmatch_table[smd->type].Match(det_ctx, p, s, smd->ctx) <= 0) {
...
}
- 对不同类型的
flowbits
进行匹配。
int DetectFlowbitMatch (DetectEngineThreadCtx *det_ctx, Packet *p,
const Signature *s, const SigMatchCtx *ctx)
{
const DetectFlowbitsData *fd = (const DetectFlowbitsData *)ctx;
if (fd == NULL)
return 0;
switch (fd->cmd) {
case DETECT_FLOWBITS_CMD_ISSET:
return DetectFlowbitMatchIsset(p,fd);
case DETECT_FLOWBITS_CMD_ISNOTSET:
return DetectFlowbitMatchIsnotset(p,fd);
case DETECT_FLOWBITS_CMD_SET:
return DetectFlowbitMatchSet(p,fd);
case DETECT_FLOWBITS_CMD_UNSET:
return DetectFlowbitMatchUnset(p,fd);
case DETECT_FLOWBITS_CMD_TOGGLE:
return DetectFlowbitMatchToggle(p,fd);
default:
SCLogError(SC_ERR_UNKNOWN_VALUE, "unknown cmd %" PRIu32 "", fd->cmd);
return 0;
}
return 0;
}
1.2.1 flowbits: set, name
在流中设置条件/名称
(如果存在)。
static int DetectFlowbitMatchSet (Packet *p, const DetectFlowbitsData *fd)
{
if (p->flow == NULL)
return 0;
FlowBitSet(p->flow,fd->idx);
return 1;
}
1.2.2 flowbits: isset, name
可在规则中使用,以确保在规则匹配且条件在流中设置时生成告警。
static int DetectFlowbitMatchIsset (Packet *p, const DetectFlowbitsData *fd)
{
if (p->flow == NULL)
return 0;
return FlowBitIsset(p->flow,fd->idx);
}
1.2.3 flowbits: toggle, name
反转当前设置。因此,如果设置了条件,则将不设置条件,反之亦然。
void FlowBitToggle(Flow *f, uint32_t idx)
{
FlowBit *fb = FlowBitGet(f, idx);
if (fb != NULL) {
FlowBitRemove(f, idx);
} else {
FlowBitAdd(f, idx);
}
}
static int DetectFlowbitMatchToggle (Packet *p, const DetectFlowbitsData *fd)
{
if (p->flow == NULL)
return 0;
FlowBitToggle(p->flow,fd->idx);
return 1;
}
1.2.4 flowbits: unset, name
可用于取消设置流中的条件。
static int DetectFlowbitMatchUnset (Packet *p, const DetectFlowbitsData *fd)
{
if (p->flow == NULL)
return 0;
FlowBitUnset(p->flow,fd->idx);
return 1;
}
1.2.5 flowbits: isnotset, name
可在规则中使用,以确保在规则匹配且条件未在流中设置时生成告警。
static int DetectFlowbitMatchIsnotset (Packet *p, const DetectFlowbitsData *fd)
{
if (p->flow == NULL)
return 0;
return FlowBitIsnotset(p->flow,fd->idx);
}
1.2.6 flowbits: noalert
此规则将不会生成告警。
static inline void DetectRulePacketRules(
ThreadVars * const tv,
DetectEngineCtx * const de_ctx,
DetectEngineThreadCtx * const det_ctx,
Packet * const p,
Flow * const pflow,
const DetectRunScratchpad *scratch
)
{
...
if (!(sflags & SIG_FLAG_NOALERT)) {
/* stateful sigs call PacketAlertAppend from DeStateDetectStartDetection */
if (!state_alert)
PacketAlertAppend(det_ctx, s, p, 0, alert_flags);
} else {
/* apply actions even if not alerting */
DetectSignatureApplyActions(p, s, alert_flags);
}
...
}
未完待续。。。