facebook

15.2.2 Пример написания парсеров

Необработанные события поступают в систему в разном формате, и для разных форматов используются специализированные алгоритмы обработки текста события (парсеры). Схема полей событий представлена в Приложении.

При создании пользовательского парсера желательно иметь в качестве примеров несколько записей о событиях одного и того же типа. Так как одно и то же событие в различных случаях может содержать или не содержать те или иные данные. Следует обратить внимание, что для пользовательских парсеров следует использовать идентификационные номера от 100000 до 120000. 

Динамические и статические поля

Статистические поля – предопределенные поля для хранения извлеченной информации из необработанного события. Всего существует 13 статистических полей (табл. 3). Однако одновременное извлечение возможно только из 8 полей. Пример:

Block of code

<decoder name="web-accesslog">

<type>web-log</type>

<prematch>^\d+.\d+.\d+.\d+ - </prematch>

<regex>^(\d+.\d+.\d+.\d+) - \S+ [\S+ -\d+] </regex>

<regex>"\w+ (\S+) HTTP\S+ (\d+) </regex>

<order>srcip,url,id</order>

</decoder>

Если списка из 13 статистических полей или одновременного извлечения 8 полей недостаточно, следует воспользоваться динамическими полями и родственными парсерами (см. пункт - Парсер для событий в формате JSON). Пример:

Block of code

<decoder name="auditd-config_change">

<parent>auditd</parent>

<regex offset="after_regex">^auid=(\S+) ses=(\S+) op="(\.+)"</regex>

<order>audit.auid,audit.session,audit.op</order>

</decoder>

Система преобразует любое поле в «<order>» в поле JSON. По умолчанию количество полей, которые можно извлечь в «<order>», равно 64.

В следующем примере показано, как парсер «Auditd» извлекает информацию из необработанного события:

Block of code

** Alert 1486483073.60589: - audit,audit_configuration,

2017 Feb 07 15:57:53 siem-example->/var/log/audit/audit.log

Rule: 80705 (level 3) -> 'Auditd: Configuration changed'

type=CONFIG_CHANGE msg=audit(1486483072.194:20): auid=0 ses=6 op="add rule" key="audit-wazuh-a" list=4 res=1

audit.type: CONFIG_CHANGE

audit.id: 20

audit.auid: 0

audit.session: 6

audit.op: add rule

audit.key: audit

audit.list: 4

audit.res: 1

Далее показан результат преобразования в формат JSON:

Block of code

{

"rule": {

"level": 3,

"description": "Auditd: Configuration changed",

"id": 80705,

"firedtimes": 2,

"groups": [

"audit",

"audit_configuration"

]

},

"agent": {

"id": "000",

"name": "wazuh-example"

},

"manager": {

"name": "wazuh-example"

},

"full_log": "type=CONFIG_CHANGE msg=audit(1486483072.194:20): auid=0 ses=6 op=\"add rule\" key=\"audit-wazuh-a\" list=4 res=1",

"audit": {

"type": "CONFIG_CHANGE",

"id": "20",

"auid": "0",

"session": "6",

"op": "add rule",

"key": "audit",

"list": "4",

"res": "1"

},

"decoder": {

"parent": "auditd",

"name": "auditd"

},

"timestamp": "2017 Feb 07 15:57:53",

"location": "/var/log/audit/audit.log"

}

Родственные парсеры

Родственные парсеры – иерархические парсеры, основная цель которых упрощение процесса парсинга для больших объемов информации из различных событий (рис.2). 

Поступившее в систему событие будет последовательно сопоставляться с каждым парсером без «родителя». Когда событие прошло соответствие условию любого из них, далее оно проходит анализ по его дочерним элементам. 

Важно понимать, что как только событие сопоставляется с определенным родительским парсером, оно перестанет просматриваться остальными из набора правил. По этой причине при построении парсеров следует воздержаться от слишком общих условий, во избежание ложных срабатываний или пропусков нужных парсеров.

В процессе сопоставления на уровне парсера используются регулярные выражения, которые требуют, чтобы совпадающая строка имела определенную структуру. Однако события часто предоставляют информацию, пропуская части или изменяя порядок, следовательно, создание множества дочерних парсеров, для соответствия каждой из возможных комбинаций, является неэффективным и непроизводительным.

Для решения данной проблемы можно создать набор дочерних парсеров, которые вместе являются «родительскими» сами по себе. В результате, когда один из этих парсеров сопоставлен, он также проверяет «родственные» парсеры, извлекая по одному фрагменту информации за раз (рис.3).

Как следствие, если порядок был изменен или появилась дополнительная информация, то анализируемый модуль сможет проанализировать и извлечь из события максимум данных.