WIP: Sigmaルールの変換用Backend作成 (#138)

* add.yea.py
This commit is contained in:
itiB
2021-11-08 18:24:40 +09:00
committed by GitHub
parent f29b7d2d1a
commit 9eca0b12d5
3 changed files with 242 additions and 0 deletions
+50
View File
@@ -0,0 +1,50 @@
# hayabusaGenerator
[![python](https://img.shields.io/badge/python-3.8-blue)](https://www.python.org/)
![version](https://img.shields.io/badge/Platform-Win-green)
![version](https://img.shields.io/badge/Platform-Lin-green)
![version](https://img.shields.io/badge/Platform-Mac-green)
[Japanese](./README.md)
`hayabusaGenerater.py` allows to convert SIGMA rules to Hayabusa ruleset.
## sigma
[https://github.com/SigmaHQ/sigma](https://github.com/SigmaHQ/sigma)
## Settings
hayabusaGenerator needs `sigmac` from the SIGMA repository.
Before using hayabusaGenerator, clone the repository.
```sh
git clone https://github.com/SigmaHQ/sigma.git
```
## Quickstart
Regist haybausa for SIGMA's backend.
```sh
export sigma_path=/path/to/sigma_repository
cp hayabusaGenerater.py $sigma_path/tools/sigma/backends
```
### Convert Single Rule
```sh
python3 $sigma_path/tools/sigmac <Target Rule> --config <config Name> --target hayabusa
```
Sample
```sh
python3 $sigma_path/tools/sigmac $sigma/rules/windows/create_remote_thread/sysmon_cactustorch.yml --config $sigma_path/tools/config/generic/sysmon.yml --target hayabusa > sysmon_cactustorch.yml
```
### Convert Multiple Rules
This is a command sample that creates a rule file from the specified directory in the current directory.
```sh
find $sigma/rules/windows/* | grep yml | xargs -I{} sh -c 'python $sigma/tools/sigmac {} --config $sigma/tools/config/generic/sysmon.yml --target hayabusa > "$(basename {})"'
```
+51
View File
@@ -0,0 +1,51 @@
# hayabusaGenerator
[![python](https://img.shields.io/badge/python-3.8-blue)](https://www.python.org/)
![version](https://img.shields.io/badge/Platform-Win-green)
![version](https://img.shields.io/badge/Platform-Lin-green)
![version](https://img.shields.io/badge/Platform-Mac-green)
[English](./README-en.md)
`hayabusaGenerator.py` はSIGMAルールをHayabusaに対応したルールセットに変更することができます。
SIGMAの持つ多くの検知ルールをHayabusaのルールセットに追加することでルールを作成する手間を省くことができます。
## sigma
[https://github.com/SigmaHQ/sigma](https://github.com/SigmaHQ/sigma)
## 環境設定
hayabusaGeneratorはSIGMAリポジトリの中にある`sigmac`を使います。
事前に任意のディレクトリにSIGMAリポジトリをcloneしてください。
```sh
git clone https://github.com/SigmaHQ/sigma.git
```
## 使い方
hayabusaGenerator.pyをSIGMAのbackendとして登録します。
```sh
export sigma_path=/path/to/sigma_repository
cp hayabusaGenerater.py $sigma_path/tools/sigma/backends
```
### 単体のルールを変換
```sh
python3 $sigma_path/tools/sigmac <変換対象ruleの指定> --config <configの指定> --target hayabusa
```
サンプル
```sh
python3 $sigma_path/tools/sigmac $sigma/rules/windows/create_remote_thread/sysmon_cactustorch.yml --config $sigma_path/tools/config/generic/sysmon.yml --target hayabusa > sysmon_cactustorch.yml
```
### 複数のルールを変換
現在のディレクトリ内に指定したディレクトリ内のルールファイルを作成するコマンドサンプルです。
```sh
find $sigma/rules/windows/* | grep yml | xargs -I{} sh -c 'python $sigma/tools/sigmac {} --config $sigma/tools/config/generic/sysmon.yml --target hayabusa > "$(basename {})"'
```
+141
View File
@@ -0,0 +1,141 @@
import copy
from collections import OrderedDict
from io import StringIO
import yaml
from sigma.backends.base import SingleTextQueryBackend
from sigma.parser.condition import SigmaAggregationParser
from sigma.parser.modifiers.base import SigmaTypeModifier
from sigma.parser.modifiers.type import SigmaRegularExpressionModifier
class HayabusaBackend(SingleTextQueryBackend):
"""Base class for backends that generate one text-based expression from a Sigma rule"""
## see tools.py
## use this value when sigmac parse argument of "-t"
identifier = "hayabusa"
active = True
# the following class variables define the generation and behavior of queries from a parse tree some are prefilled with default values that are quite usual
andToken = " and " # Token used for linking expressions with logical AND
orToken = " or " # Same for OR
notToken = " not " # Same for NOT
subExpression = "(%s)" # Syntax for subexpressions, usually parenthesis around it. %s is inner expression
valueExpression = "%s" # Expression of values, %s represents value
typedValueExpression = dict() # Expression of typed values generated by type modifiers. modifier identifier -> expression dict, %s represents value
sort_condition_lists = False
mapListsSpecialHandling = True
name_idx = 1
selection_prefix = "SELECTION_{0}"
name_2_selection = OrderedDict()
def __init__(self, sigmaconfig, options):
super().__init__(sigmaconfig)
def cleanValue(self, val):
return val
def generateListNode(self, node):
return self.generateORNode(node)
def create_new_selection(self):
name = self.selection_prefix.format(self.name_idx)
self.name_idx+=1
return name
def generateMapItemNode(self, node):
fieldname, value = node
transformed_fieldname = self.fieldNameMapping(fieldname, value)
if self.mapListsSpecialHandling == False and type(value) in (str, int, list) or self.mapListsSpecialHandling == True and type(value) in (str, int):
name = self.create_new_selection()
self.name_2_selection[name] = [(transformed_fieldname, self.generateNode(value))]
return name
elif type(value) == list:
return self.generateMapItemListNode(transformed_fieldname, value)
elif isinstance(value, SigmaTypeModifier):
return self.generateMapItemTypedNode(transformed_fieldname, value)
elif value is None:
return self.generateNode((transformed_fieldname+"|re","^$")) #nullは正規表現で表す。これでいいのかちょっと不安
else:
raise TypeError("Backend does not support map values of type " + str(type(value)))
def generateMapItemTypedNode(self, fieldname, value):
# `|re`オプションに対応
if type(value) == SigmaRegularExpressionModifier:
fieldname = fieldname + "|re"
return self.generateNode((fieldname,value.value))
else:
raise NotImplementedError("Type modifier '{}' is not supported by backend".format(value.identifier))
def generateMapItemListNode(self, fieldname, value):
### 下記のようなケースに対応
### selection:
### EventID:
### - 1
### - 2
### 基本的にリストはORと良く、generateListNodeもORNodeを生成している。
### しかし、上記のケースでgenerateListNode()を実行すると、下記のようなYAMLになってしまう。
### selection:
### EventID: 1 or 2
### 上記のようにならないように、修正している。
### なお、generateMapItemListNode()を有効にするために、self.mapListsSpecialHandling = Trueとしている
list_values = list()
for sub_node in value:
list_values.append((fieldname,sub_node))
return self.subExpression % self.generateORNode(list_values)
def generateAggregation(self, agg):
# python3 tools/sigmac rules/windows/process_creation/win_dnscat2_powershell_implementation.yml --config tools/config/generic/sysmon.yml --target hayabusa
if agg == None:
return ""
if agg.aggfunc == SigmaAggregationParser.AGGFUNC_COUNT:
# condition の中に "|" は1つのみ
# | 以降をそのまま出力する
target = '|'
index = agg.parser.parsedyaml["detection"]["condition"].find(target)
return agg.parser.parsedyaml["detection"]["condition"][index:]
## count以外は対応していないので、エラーを返す
raise NotImplementedError("This rule contains aggregation operator not implemented for this backend")
def generateValueNode(self, node):
## このメソッドをオーバーライドしておかないとint型もstr型として扱われてしまうので、int型やint型として、str型はstr型として処理するために実装した。
## このメソッドは最悪無くてもいいような気もする。
if type(node) == int:
return node
else:
return self.valueExpression % (self.cleanValue(str(node)))
def generateQuery(self, parsed):
result = self.generateNode(parsed.parsedSearch)
if parsed.parsedAgg:
res = self.generateAggregation(parsed.parsedAgg)
result += res
ret = ""
with StringIO() as bs:
## 元のyamlをいじるとこの後の処理に影響を与える可能性があるので、deepCopyする
parsed_yaml = copy.deepcopy(parsed.sigmaParser.parsedyaml)
## なんかタイトルは先頭に来てほしいので、そのための処理
## parsed.sigmaParser.parsedyamlがOrderedDictならこんなことしなくていい、後で別のやり方があるか調べる
## 順番固定してもいいかも
bs.write("title: " + parsed_yaml["title"]+"\n")
del parsed_yaml["title"]
## detectionの部分だけ変更して出力する。
parsed_yaml["detection"] = {}
parsed_yaml["detection"]["condition"] = result
for key, values in self.name_2_selection.items():
parsed_yaml["detection"][key] = {}
for fieldname, value in values:
parsed_yaml["detection"][key][fieldname] = value
yaml.dump(parsed_yaml, bs, indent=4, default_flow_style=False)
ret = bs.getvalue()
return ret