Compare commits

...

89 Commits

Author SHA1 Message Date
Thomas Patzke feb836cbf2 Sigmatools release 0.14 2019-11-10 00:09:59 +01:00
Florian Roth 8cc16d252a fix: more FP reductions 2019-11-09 23:36:29 +01:00
Florian Roth 038f205f0f fix: FPs with UserInitMprLogonScript rule 2019-11-09 23:32:53 +01:00
Florian Roth fbe138ed90 rule: reduced level of rule to medium due to FPs 2019-11-09 23:24:31 +01:00
Florian Roth faeccf0c3d Merge branch 'master' into devel 2019-11-09 22:42:16 +01:00
Florian Roth a0beda240c fix: fixed wrong field mapping in windows-audit source config 2019-11-09 22:42:00 +01:00
Florian Roth ef0af10747 Merge pull request #521 from Neo23x0/devel
fix: fixed false positive in suspicious shell spawn rule
2019-11-09 12:50:50 +01:00
Florian Roth 9835950f04 rule: SID to AD object rule level adjusted 2019-11-09 12:49:54 +01:00
Florian Roth be62fad5cc fix: fixed false positive in suspicious shell spawn rule 2019-11-09 10:45:46 +01:00
Thomas Patzke 465e41bfbb Added regular expression support in es-dsl backend 2019-11-08 22:31:02 +01:00
Thomas Patzke 8b7560c2f4 Added changelog 2019-11-07 23:08:44 +01:00
Thomas Patzke ef14ee542d Added modifiers: startswith and endswith 2019-11-05 23:04:13 +01:00
Thomas Patzke 97d13660f7 Merge pull request #517 from Neo23x0/devel
Firewall Deactivation Rule
2019-11-05 22:54:50 +01:00
Thomas Patzke 7a81054cdd Merge pull request #518 from refractionPOINT/master
LimaCharlie Productionization
2019-11-05 22:54:01 +01:00
Maxime Lamothe-Brassard 1b9054c1f3 Adding some comments 2019-11-05 08:39:24 -05:00
Maxime Lamothe-Brassard b7018bcd4a Adding a post-mapper mechanism to fix some common issues in Sigma rules to LC. 2019-11-05 08:39:24 -05:00
Maxime Lamothe-Brassard c2e621cf08 Fixing another edge case with string escape. 2019-11-05 08:39:24 -05:00
Maxime Lamothe-Brassard 0c6b9e532b Remove debugging statement 2019-11-05 08:39:24 -05:00
Maxime Lamothe-Brassard 6f2f1d2bd7 Add ability to map fields and values based on callbacks. 2019-11-05 08:39:24 -05:00
Maxime Lamothe-Brassard 0b9a3f3a08 Refactor to better support keyword fields. 2019-11-05 08:39:24 -05:00
Maxime Lamothe-Brassard 9aedb8f764 Adding another exception case to get more "contains" shortcuts instead of REs. 2019-11-05 08:39:24 -05:00
Maxime Lamothe-Brassard 102ab3081b Fix the convertion from simple wildcard strings to a full regular expression so that it is always correct. The previous solution just mostly-worked. 2019-11-05 08:39:24 -05:00
Maxime Lamothe-Brassard e52f29dda9 Fix matches operator field set to value instead of re. 2019-11-05 08:38:06 -05:00
Florian Roth c60563e546 rule: add modified rule date 2019-11-05 11:24:52 +01:00
Florian Roth 5786688f97 rule: Firewall disabled via Netsh 2019-11-04 16:10:10 +01:00
Thomas Patzke 54c75167ce Default configurations for backends 2019-11-03 23:32:50 +01:00
Thomas Patzke 0c64992276 Merge branch 'master' of https://github.com/Neo23x0/sigma 2019-11-02 23:05:41 +01:00
Thomas Patzke a5579fa8cd Merge pull request #513 from Karneades/fix-sysmon-rule
fix: bound sysmon logon script rule to field
2019-11-02 23:04:35 +01:00
Thomas Patzke c0f1b12833 Merge pull request #512 from Karneades/fix-win-rules
fix: bound windows event log rules to message field
2019-11-02 23:03:44 +01:00
Thomas Patzke 66d9de460d Merge branch 'master' of https://github.com/Neo23x0/sigma 2019-11-02 22:56:32 +01:00
Thomas Patzke 4f19ef5708 Graylog backend now derived from es-qs
Technically, Graylog is ES. Fixes and improvements for ES didn't
propagate to Graylog, now they do.
2019-11-02 22:56:01 +01:00
Thomas Patzke 8af2b70594 Restrict search not bound to fields to keyword fields 2019-11-02 22:55:04 +01:00
Thomas Patzke c9eb921f68 ConditionAND/OR constructor now allows arbeitrary number of operands 2019-11-02 22:54:35 +01:00
Karneades 0117dac1db fix: bound sysmon logon script rule to field
Fixed rule:
- rules/windows/sysmon/sysmon_logon_scripts_userinitmprlogonscript.yml
2019-11-02 11:47:20 +01:00
Karneades 68fd20cb66 fix: bound windows event log rules to message field
Fixed rules
- rules/windows/builtin/win_susp_msmpeng_crash.yml
- rules/windows/builtin/win_alert_active_directory_user_control.yml
- rules/windows/builtin/win_av_relevant_match.yml
- rules/windows/builtin/win_mal_creddumper.yml
- rules/windows/builtin/win_susp_sam_dump.yml
- rules/windows/builtin/win_alert_mimikatz_keywords.yml
- rules/windows/builtin/win_alert_enable_weak_encryption.yml
2019-11-02 11:25:29 +01:00
Florian Roth 3107c0c268 rule: Formbook rule improved 2019-10-31 09:32:18 +01:00
Florian Roth 4741b6a4d6 rule: Mustang Panda dropper 2019-10-30 18:22:40 +01:00
Florian Roth d661771608 rule: another DTRACK reference 2019-10-30 18:22:25 +01:00
Florian Roth 3ac28f3eed rule: DTRACK process creation 2019-10-30 15:16:33 +01:00
Thomas Patzke 219f00e3fb Added command line parameter
Implements #418
2019-10-29 23:04:28 +01:00
Thomas Patzke 2eeccf48e0 Removed line breaks in Elastalert YAML output
Fixes #453
2019-10-29 22:45:37 +01:00
Thomas Patzke f4e9690d6b Merge pull request #508 from Karneades/fixRule3
fix: bound keywords to field in multiple PS rules
2019-10-29 22:34:08 +01:00
Thomas Patzke 78d8ca2b41 Merge pull request #507 from Karneades/fixRule2
fix: bound keywords to field in PS cred prompt rule
2019-10-29 22:31:01 +01:00
Thomas Patzke 40df0d4534 Merge pull request #506 from Karneades/fixRule1
fix: bound keywords to field in WMI persistence rule
2019-10-29 22:30:27 +01:00
Thomas Patzke 6eb49fc1ce Merge pull request #509 from Karneades/fixRule4
fix: change keyword and bound it to a field in PS rule
2019-10-29 22:27:54 +01:00
Thomas Patzke b6403793c1 Fixed escaping in rule 2019-10-29 22:06:23 +01:00
Karneades ab5556ae8c fix: change keyword and bound it to a field 2019-10-29 19:59:43 +01:00
Karneades aafab2e936 fix: bound keywords to field in multiple PS rules
Rules changed:
- rules/windows/powershell/powershell_malicious_commandlets.yml
- rules/windows/powershell/powershell_malicious_keywords.yml
- rules/windows/powershell/powershell_suspicious_download.yml
- rules/windows/powershell/powershell_suspicious_invocation_specific.yml
2019-10-29 19:53:18 +01:00
Karneades f31750e567 fix: bound keywords to field in PS cred prompt rule 2019-10-29 19:43:04 +01:00
Karneades cd20e4a3fc fix: bound keywords to field in WMI persistence rule
See #501.
2019-10-29 19:22:41 +01:00
Thomas Patzke 632c45843b Merge pull request #500 from refractionPOINT/master
Adding LimaCharlie to the README's supported targets.
2019-10-28 21:17:30 +01:00
Maxime Lamothe-Brassard f01913c996 Adding LimaCharlie to the README's supported targets. 2019-10-28 14:48:04 -05:00
Thomas Patzke 6a76f5950b Merge pull request #499 from refractionPOINT/master
Adding Backend for LimaCharlie D&R rules
2019-10-28 20:38:33 +01:00
Maxime Lamothe-Brassard f6fb9c7f5f Fixing typo in response metadata. 2019-10-28 11:31:50 -05:00
Maxime Lamothe-Brassard 2873e1ded3 Small refactors to make more readable and remove deprecated code paths to increase coverage. 2019-10-28 10:49:05 -05:00
Florian Roth 8ff85499c8 rule: svchost dll search order hijack 2019-10-28 12:03:03 +01:00
Florian Roth 1a3444d0ef docs: comment on rule expression 2019-10-28 12:02:46 +01:00
Maxime Lamothe-Brassard a7003c2aa3 Adding support for "unix", looking like a mistake by the creator. 2019-10-27 15:55:12 -05:00
Maxime Lamothe-Brassard d019cef439 Ading a bit more of early support for netflow and some linux exe. 2019-10-27 15:48:28 -05:00
Maxime Lamothe-Brassard a57a7b58cf Added conceptial support for aliasing keyworkds to a specific field depending on the log source. 2019-10-27 15:28:54 -05:00
Maxime Lamothe-Brassard 60b20a76a6 Fixing handling of unsupported sources. 2019-10-27 12:37:06 -05:00
Maxime Lamothe-Brassard 0fe72d6133 Emit error on full-text searches not being supported. 2019-10-27 12:26:36 -05:00
Maxime Lamothe-Brassard f43300af8e Fix the top level pre-condition for Windows Event Logs on LC. 2019-10-27 12:17:15 -05:00
Maxime Lamothe-Brassard 91e48d8c1b Adding setup links and fixing test that would crash Not node, but not seen in prod rules. 2019-10-27 11:56:32 -05:00
Maxime Lamothe-Brassard 8d866b0868 Adding comments. 2019-10-26 17:37:13 -05:00
Maxime Lamothe-Brassard bc5e9bd03a Making rule output a full D&R (with the Response component) and includes a lot of metadata from the rule in the report. 2019-10-26 17:30:40 -05:00
Maxime Lamothe-Brassard 8cc3990aef Extending support for more random rules with odd names. 2019-10-26 16:59:33 -05:00
Maxime Lamothe-Brassard 4d65b62063 Adding support for generating rules for Windows builtin category for use in the External Logs of LC. 2019-10-26 16:30:50 -05:00
Maxime Lamothe-Brassard 30cc7ee809 Refactor mappings into a flat structure to account for missing parameters in some combinations. 2019-10-26 16:09:39 -05:00
Maxime Lamothe-Brassard 77329714c5 Adding service to indirection of mappings since it will be used for Windows Event Logs. 2019-10-26 16:06:42 -05:00
Maxime Lamothe-Brassard 823d86c7d9 Remove unimplemented config entries and fix bug with valueNode. 2019-10-26 15:54:08 -05:00
Maxime Lamothe-Brassard bba43c7a86 First draft of support for LimaCharlie D&R rules. 2019-10-26 15:45:48 -05:00
Florian Roth 66a32549f1 rule: proxy malware ua - Zebrocy 2019-10-26 14:20:29 +02:00
Florian Roth 42808b7eb8 rule: webshell detection improved 2019-10-26 09:14:54 +02:00
Thomas Patzke 30948b9c1a Added sigma-similarity tool
Fixed also bug in backend base class that was triggered by the way
backends are used by this tool.
2019-10-25 21:59:03 +02:00
Florian Roth a5ec6722a1 rule: the actual changes to hwp rule 2019-10-24 15:35:13 +02:00
Florian Roth 86c1b4ae4b rule: hwp exploits 2019-10-24 11:46:56 +02:00
Florian Roth 3d4ce9d175 rule: another reference link for 'execution by ordinal' 2019-10-22 15:18:19 +02:00
Florian Roth b3654947bc rule: suspicious call by ordinal (rundll32) 2019-10-22 12:40:26 +02:00
Florian Roth 0f02f2bdfc rule: adjusted very noisy rule on AppLocker whitelist bypass 2019-10-22 12:32:37 +02:00
Florian Roth 3bd3e724f1 Merge pull request #473 from joesecurity/patch-3
Update README.md
2019-10-21 13:34:41 +02:00
Florian Roth 439045a87b Reordered projects 2019-10-21 13:34:30 +02:00
Florian Roth 4e7ad5c948 rule: added date to crypto miner rule 2019-10-21 13:24:33 +02:00
Florian Roth e8963b2599 rule: crypto miner user agents in proxy logs 2019-10-21 13:21:50 +02:00
Joe Security b815b15255 Update README.md
Added Joe Sandbox to list of supported Projects or Products.
2019-10-21 13:13:49 +02:00
Florian Roth c8b5b91815 Merge pull request #471 from a2tf/rule_change_proxy_uri_to_url
rule: changed two proxy rules from uri-query to url
2019-10-21 12:52:36 +02:00
Florian Roth 9457f01c29 Update proxy_ios_implant.yml 2019-10-21 11:20:11 +02:00
Florian Roth f8d8eb7948 Update proxy_chafer_malware.yml 2019-10-21 11:19:59 +02:00
a2tf a2753ba5a6 rule: changed two proxy rules from uri-query to url 2019-10-18 14:15:39 +00:00
60 changed files with 1433 additions and 290 deletions
+97
View File
@@ -0,0 +1,97 @@
# Release Notes
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html)
from version 0.14.0.
## Unreleased
Changes from this section will be contained in the next release.
## 0.14
### Added
* sigma-similarity tool
* LimaCharlie backend
* Default configurations for some backends that are used if no configuration is passed.
* Regular expression support for es-dsl backend (propagates to backends derived from this like elastalert-dsl)
* Value modifiers:
* startswith
* endswith
### Changed
* Removal of line breaks in elastalert output
* Searches not bound to fields are restricted to keyword fields in es-qs backend
* Graylog backend now based on es-qs backend
### Fixed
* Removed ProcessCommandLine mapping for Windows Security EventID 4688 in generic
process creation log source configuration.
## 0.13
### Added
* Index mappings for Sumologic
* Malicious cmdlets in wdatp
* QRadar support for keyword searches
* QRadar mapping improvements
* QRadar field selection
* QRadar type regex modifier support
* Elasticsearch keyword field blacklisting with wildcards
* Added dateField configuration parameter in xpack-watcher backend
* Field mappings in configurations
* Field name mapping for conditional fields
* Value modifiers:
* utf16
* utf16le
* wide
* utf16be
### Changed
* Improved --backend-config help text
### Fixed
* Backend errors in ala
* Slash escaping within es-dsl wildcard queries
* QRadar backend config
* QRadar field name and value escaping and handling
* Elasticsearch wildcard detection pattern
* Aggregation on keyword field in es-dsl backend
## 0.12.1
### Fixed
* Missing build dependency
## 0.12
### Added
* Usage of "Channel" field in ELK Windows configuration
* Fields to mappings
* xpack-watcher actions index and webhook
* Config for Winlogbeat 7.x
* Value modifiers
* Regular expression support
### Changed
* Warning/error messages
* Sumologic value cleaning
* Explicit OR for Elasticsearch query strings
* Listing of available configurations on missing configuration error
### Fixed
* Conditions in es-dsl backend
* Sumologic handling of null values
* Ignore timeframe detection keyword in all/any of conditions
+38
View File
@@ -0,0 +1,38 @@
## {{ version.minor }}.{{ version.major }}.{{ version.patch }} ({{ date }})
### Added
{% for item in added %}
* {{ item | indent(2) }}
{% endfor %}
### Changed
{% for item in changed %}
* {{ item | indent(2) }}
{% endfor %}
### Deprecated
{% for item in deprecated %}
* {{ item | indent(2) }}
{% endfor %}
### Removed
{% for item in removed %}
* {{ item | indent(2) }}
{% endfor %}
### Fixed
{% for item in fixed %}
* {{ item | indent(2) }}
{% endfor %}
### Security
{% for item in security %}
* {{ item | indent(2) }}
{% endfor %}
+1
View File
@@ -39,6 +39,7 @@ test-sigmac:
coverage run -a --include=$(COVSCOPE) tools/sigmac -rvdI -t powershell -c tools/config/powershell.yml -Ocsv rules/ > /dev/null
coverage run -a --include=$(COVSCOPE) tools/sigmac -rvdI -t arcsight -c tools/config/arcsight.yml rules/ > /dev/null
coverage run -a --include=$(COVSCOPE) tools/sigmac -rvdI -t qradar -c tools/config/qradar.yml rules/ > /dev/null
coverage run -a --include=$(COVSCOPE) tools/sigmac -rvdI -t limacharlie -c tools/config/limacharlie.yml rules/ > /dev/null
coverage run -a --include=$(COVSCOPE) tools/sigmac -rvdI -t qualys -c tools/config/qualys.yml rules/ > /dev/null
coverage run -a --include=$(COVSCOPE) tools/sigmac -rvdI -t netwitness -c tools/config/netwitness.yml rules/ > /dev/null
coverage run -a --include=$(COVSCOPE) tools/sigmac -rvdI -t sumologic -O rulecomment -c tools/config/sumologic.yml rules/ > /dev/null
+1
View File
@@ -12,6 +12,7 @@ elasticsearch = "*"
elasticsearch-async = "*"
pymisp = "*"
PyYAML = ">=3.11"
progressbar2 = "*"
[requires]
python_version = "3.6"
Generated
+86 -60
View File
@@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
"sha256": "5e571aa1a1b4f78e71563cc30e3f457c8359c36888c76b6ed68376dadce445bb"
"sha256": "f3f1c14d8b9cfcd5608e018017012b8712a94fb7a56f633ae179bd3451d636fb"
},
"pipfile-spec": 6,
"requires": {
@@ -18,30 +18,20 @@
"default": {
"aiohttp": {
"hashes": [
"sha256:00d198585474299c9c3b4f1d5de1a576cc230d562abc5e4a0e81d71a20a6ca55",
"sha256:0155af66de8c21b8dba4992aaeeabf55503caefae00067a3b1139f86d0ec50ed",
"sha256:09654a9eca62d1bd6d64aa44db2498f60a5c1e0ac4750953fdd79d5c88955e10",
"sha256:199f1d106e2b44b6dacdf6f9245493c7d716b01d0b7fbe1959318ba4dc64d1f5",
"sha256:296f30dedc9f4b9e7a301e5cc963012264112d78a1d3094cd83ef148fdf33ca1",
"sha256:368ed312550bd663ce84dc4b032a962fcb3c7cae099dbbd48663afc305e3b939",
"sha256:40d7ea570b88db017c51392349cf99b7aefaaddd19d2c78368aeb0bddde9d390",
"sha256:629102a193162e37102c50713e2e31dc9a2fe7ac5e481da83e5bb3c0cee700aa",
"sha256:6d5ec9b8948c3d957e75ea14d41e9330e1ac3fed24ec53766c780f82805140dc",
"sha256:87331d1d6810214085a50749160196391a712a13336cd02ce1c3ea3d05bcf8d5",
"sha256:9a02a04bbe581c8605ac423ba3a74999ec9d8bce7ae37977a3d38680f5780b6d",
"sha256:9c4c83f4fa1938377da32bc2d59379025ceeee8e24b89f72fcbccd8ca22dc9bf",
"sha256:9cddaff94c0135ee627213ac6ca6d05724bfe6e7a356e5e09ec57bd3249510f6",
"sha256:a25237abf327530d9561ef751eef9511ab56fd9431023ca6f4803f1994104d72",
"sha256:a5cbd7157b0e383738b8e29d6e556fde8726823dae0e348952a61742b21aeb12",
"sha256:a97a516e02b726e089cffcde2eea0d3258450389bbac48cbe89e0f0b6e7b0366",
"sha256:acc89b29b5f4e2332d65cd1b7d10c609a75b88ef8925d487a611ca788432dfa4",
"sha256:b05bd85cc99b06740aad3629c2585bda7b83bd86e080b44ba47faf905fdf1300",
"sha256:c2bec436a2b5dafe5eaeb297c03711074d46b6eb236d002c13c42f25c4a8ce9d",
"sha256:cc619d974c8c11fe84527e4b5e1c07238799a8c29ea1c1285149170524ba9303",
"sha256:d4392defd4648badaa42b3e101080ae3313e8f4787cb517efd3f5b8157eaefd6",
"sha256:e1c3c582ee11af7f63a34a46f0448fca58e59889396ffdae1f482085061a2889"
"sha256:1e984191d1ec186881ffaed4581092ba04f7c61582a177b187d3a2f07ed9719e",
"sha256:259ab809ff0727d0e834ac5e8a283dc5e3e0ecc30c4d80b3cd17a4139ce1f326",
"sha256:2f4d1a4fdce595c947162333353d4a44952a724fba9ca3205a3df99a33d1307a",
"sha256:32e5f3b7e511aa850829fbe5aa32eb455e5534eaa4b1ce93231d00e2f76e5654",
"sha256:344c780466b73095a72c616fac5ea9c4665add7fc129f285fbdbca3cccf4612a",
"sha256:460bd4237d2dbecc3b5ed57e122992f60188afe46e7319116da5eb8a9dfedba4",
"sha256:4c6efd824d44ae697814a2a85604d8e992b875462c6655da161ff18fd4f29f17",
"sha256:50aaad128e6ac62e7bf7bd1f0c0a24bc968a0c0590a726d5a955af193544bcec",
"sha256:6206a135d072f88da3e71cc501c59d5abffa9d0bb43269a6dcd28d66bfafdbdd",
"sha256:65f31b622af739a802ca6fd1a3076fd0ae523f8485c52924a89561ba10c49b48",
"sha256:ae55bac364c405caa23a4f2d6cfecc6a0daada500274ffca4a9230e7129eac59",
"sha256:b778ce0c909a2653741cb4b1ac7015b5c130ab9c897611df43ae6a58523cb965"
],
"version": "==3.5.4"
"version": "==3.6.2"
},
"async-timeout": {
"hashes": [
@@ -52,17 +42,17 @@
},
"attrs": {
"hashes": [
"sha256:69c0dbf2ed392de1cb5ec704444b08a5ef81680a61cb899dc08127123af36a79",
"sha256:f0b870f674851ecbfbbbd364d6b5cbdff9dcedbc7f3f5e18a6891057f21fe399"
"sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c",
"sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"
],
"version": "==19.1.0"
"version": "==19.3.0"
},
"certifi": {
"hashes": [
"sha256:046832c04d4e752f37383b628bc601a7ea7211496b4638f6514d0e5b9acc4939",
"sha256:945e3ba63a0b9f577b1395204e13c3a231f9bc0223888be653286534e5873695"
"sha256:e4f3620cfea4f83eedc95b24abd9cd56f3c4b146dd0177e83a21b4eb49e21e50",
"sha256:fd7c7c74727ddcf00e9acd26bba8da604ffec95bf1c2144e67aff7a8b50e6cef"
],
"version": "==2019.6.16"
"version": "==2019.9.11"
},
"chardet": {
"hashes": [
@@ -118,11 +108,11 @@
},
"elasticsearch": {
"hashes": [
"sha256:cbc73831c63fa2824538df76fcb2c4be007b43dbd9e7788ae70ea6d24109925b",
"sha256:d1b176b87a7fb75dca82978c82a4023e8b21cbc98f4018cb51190fb0b8b43764"
"sha256:693935914d59a517dfffdaab547ff906712a386d9e25027517464960221cbd4c",
"sha256:7644fa0a9ae524344185bda561826a781a5c6bd4d3eb98a24515c567aab88327"
],
"index": "pypi",
"version": "==7.0.2"
"version": "==7.0.5"
},
"elasticsearch-async": {
"hashes": [
@@ -146,12 +136,26 @@
"markers": "python_version < '3.7'",
"version": "==1.1.0"
},
"importlib-metadata": {
"hashes": [
"sha256:aa18d7378b00b40847790e7c27e11673d7fed219354109d0e7b9e5b25dc3ad26",
"sha256:d5f18a79777f3aa179c145737780282e27b508fc8fd688cb17c7a813e8bd39af"
],
"version": "==0.23"
},
"jsonschema": {
"hashes": [
"sha256:5f9c0a719ca2ce14c5de2fd350a64fd2d13e8539db29836a86adc990bb1a068f",
"sha256:8d4a2b7b6c2237e0199c8ea1a6d3e05bf118e289ae2b9d7ba444182a2959560d"
"sha256:2fa0684276b6333ff3c0b1b27081f4b2305f0a36cf702a23db50edb141893c3f",
"sha256:94c0a13b4a0616458b42529091624e66700a17f847453e52279e35509a5b7631"
],
"version": "==3.0.2"
"version": "==3.1.1"
},
"more-itertools": {
"hashes": [
"sha256:409cd48d4db7052af495b09dec721011634af3753ae1ef92d2b32f73a745f832",
"sha256:92b8c4b06dac4f0611c0729b2f2ede52b2e1bac1ab48f089c7ddc12e26bb60c4"
],
"version": "==7.2.0"
},
"multidict": {
"hashes": [
@@ -189,31 +193,46 @@
},
"pathspec": {
"hashes": [
"sha256:54a5eab895d89f342b52ba2bffe70930ef9f8d96e398cccf530d21fa0516a873"
"sha256:e285ccc8b0785beadd4c18e5708b12bb8fcf529a1e61215b3feff1d1e559ea5c"
],
"version": "==0.5.9"
"version": "==0.6.0"
},
"progressbar2": {
"hashes": [
"sha256:7538d02045a1fd3aa2b2834bfda463da8755bd3ff050edc6c5ddff3bc616215f",
"sha256:eb774d1e0d03ea4730f381c13c2c6ae7abb5ddfb14d8321d7a58a61aa708f0d0"
],
"index": "pypi",
"version": "==3.47.0"
},
"pymisp": {
"hashes": [
"sha256:5bff5e7705d2697fd6e7110d1f316688d6106795cba4d453eec8c78c18b0e9f7",
"sha256:85d319e0e1d4e53a901501ad74679f3802201b5e12df2da443aaae1d2443e3b1",
"sha256:a2fe66bada1186abc6237dc151473e307619685b8168aaeb31b6112528638d9e"
"sha256:17b145dbc39a1ba4ebce60e8b75a479d2c8fd3c2a239f32682f2e1a3636469ec",
"sha256:814023f346f9e1dcf6763d93450df44ff0157f2061c612a7eaf2020280f588a3",
"sha256:de67196f6a8916b9c52a84a1c45ea967c53fa9d2b3795b070ad2c1cbc28d79d7"
],
"index": "pypi",
"version": "==2.4.112"
"version": "==2.4.117.2"
},
"pyrsistent": {
"hashes": [
"sha256:34b47fa169d6006b32e99d4b3c4031f155e6e68ebcc107d6454852e8e0ee6533"
"sha256:eb6545dbeb1aa69ab1fb4809bfbf5a8705e44d92ef8fc7c2361682a47c46c778"
],
"version": "==0.15.4"
"version": "==0.15.5"
},
"python-dateutil": {
"hashes": [
"sha256:7e6584c74aeed623791615e26efd690f29817a27c73085b78e4bad02493df2fb",
"sha256:c89805f6f4d64db21ed966fda138f8a5ed7a4fdbc1a8ee329ce1b74e3c74da9e"
"sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c",
"sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"
],
"version": "==2.8.0"
"version": "==2.8.1"
},
"python-utils": {
"hashes": [
"sha256:34aaf26b39b0b86628008f2ae0ac001b30e7986a8d303b61e1357dfcdad4f6d3",
"sha256:e25f840564554eaded56eaa395bca507b0b9e9f0ae5ecb13a8cb785305c56d25"
],
"version": "==2.3.0"
},
"pyyaml": {
"hashes": [
@@ -243,26 +262,26 @@
},
"six": {
"hashes": [
"sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c",
"sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"
"sha256:1f1b7d42e254082a9db6279deae68afb421ceba6158efa6131de7b3003ee93fd",
"sha256:30f610279e8b2578cab6db20741130331735c781b56053c59c4076da27f06b66"
],
"version": "==1.12.0"
"version": "==1.13.0"
},
"typing-extensions": {
"hashes": [
"sha256:2ed632b30bb54fc3941c382decfd0ee4148f5c591651c9272473fea2c6397d95",
"sha256:b1edbbf0652660e32ae780ac9433f4231e7339c7f9a8057d0f042fcbcea49b87",
"sha256:d8179012ec2c620d3791ca6fe2bf7979d979acdbef1fca0bc56b37411db682ed"
"sha256:091ecc894d5e908ac75209f10d5b4f118fbdb2eb1ede6a63544054bb1edb41f2",
"sha256:910f4656f54de5993ad9304959ce9bb903f90aadc7c67a0bef07e678014e892d",
"sha256:cf8b63fedea4d89bab840ecbb93e75578af28f76f66c35889bd7065f5af88575"
],
"markers": "python_version < '3.7'",
"version": "==3.7.4"
"version": "==3.7.4.1"
},
"urllib3": {
"hashes": [
"sha256:b246607a25ac80bedac05c6f282e3cdaf3afb65420fd024ac94435cabe6e18d1",
"sha256:dbe59173209418ae49d485b87d1681aefa36252ee85884c31346debd19463232"
"sha256:3de946ffbed6e6746608990594d08faac602528ac7015ac28d33cee6a45b7398",
"sha256:9a107b99a5393caf59c7aa3c1249c16e6879447533d0887f4336dde834c7be86"
],
"version": "==1.25.3"
"version": "==1.25.6"
},
"wrapt": {
"hashes": [
@@ -272,11 +291,11 @@
},
"yamllint": {
"hashes": [
"sha256:9a4fec2d40804979de5f54453fd1551bc1f8b59a7ad4a26fd7f26aeca34a83af",
"sha256:f97cd763fe7b588444a94cc44fd3764b832a613b5250baa2bfe8b84c91e4c330"
"sha256:24f05b7ff1a604120eeb5ff7afb7ed8792253bfa96ee83db9cec6d5c20feaf64",
"sha256:d42dbb35b3d28722a8c5c25de4593add0a6215b2732eb6932d89f38482c3d01c"
],
"index": "pypi",
"version": "==1.16.0"
"version": "==1.18.0"
},
"yarl": {
"hashes": [
@@ -293,6 +312,13 @@
"sha256:e060906c0c585565c718d1c3841747b61c5439af2211e185f6739a9412dfbde1"
],
"version": "==1.3.0"
},
"zipp": {
"hashes": [
"sha256:3718b1cbcd963c7d4c5511a8240812904164b7f381b647143a89d3b98f9bcd8e",
"sha256:f06903e9f1f43b12d371004b4ac7b06ab39a44adc747266928ae6debfa7b3335"
],
"version": "==0.6.0"
}
},
"develop": {}
+7 -5
View File
@@ -100,7 +100,7 @@ merges multiple YAML documents of a Sigma rule collection into simple Sigma rule
```
usage: sigmac [-h] [--recurse] [--filter FILTER]
[--target {arcsight,es-qs,es-dsl,kibana,xpack-watcher,elastalert,graylog,logpoint,grep,netwitness,powershell,qradar,qualys,splunk,splunkxml,sumologic,fieldlist,wdatp}]
[--target {arcsight,es-qs,es-dsl,kibana,xpack-watcher,elastalert,graylog,limacharlie,logpoint,grep,netwitness,powershell,qradar,qualys,splunk,splunkxml,sumologic,fieldlist,wdatp}]
[--target-list] [--config CONFIG] [--output OUTPUT]
[--backend-option BACKEND_OPTION] [--defer-abort]
[--ignore-backend-errors] [--verbose] [--debug]
@@ -125,7 +125,7 @@ optional arguments:
tag that must appear in the rules tag list, case-
insensitive matching. Multiple log source
specifications are AND linked.
--target {arcsight,es-qs,es-dsl,kibana,xpack-watcher,elastalert,graylog,logpoint,grep,netwitness,powershell,qradar,qualys,splunk,splunkxml,sumologic,fieldlist,wdatp}, -t {arcsight,es-qs,es-dsl,kibana,xpack-watcher,elastalert,graylog,logpoint,grep,netwitness,powershell,qradar,qualys,splunk,splunkxml,sumologic,fieldlist,wdatp}
--target {arcsight,es-qs,es-dsl,kibana,xpack-watcher,elastalert,graylog,limacharlie,logpoint,grep,netwitness,powershell,qradar,qualys,splunk,splunkxml,sumologic,fieldlist,wdatp}, -t {arcsight,es-qs,es-dsl,kibana,xpack-watcher,elastalert,graylog,limacharlie,logpoint,grep,netwitness,powershell,qradar,qualys,splunk,splunkxml,sumologic,fieldlist,wdatp}
Output target format
--target-list, -l List available output target formats
--config CONFIG, -c CONFIG
@@ -195,6 +195,7 @@ tools/sigmac -t splunk -c ~/my-splunk-mapping.yml -c tools/config/generic/window
* [RSA NetWitness](https://www.rsa.com/en-us/products/threat-detection-response)
* [PowerShell](https://docs.microsoft.com/en-us/powershell/scripting/getting-started/getting-started-with-windows-powershell?view=powershell-6)
* [Grep](https://www.gnu.org/software/grep/manual/grep.html) with Perl-compatible regular expression support
* [LimaCharlie](https://limacharlie.io)
Current work-in-progress
* [Splunk Data Models](https://docs.splunk.com/Documentation/Splunk/7.1.0/Knowledge/Aboutdatamodels)
@@ -271,12 +272,13 @@ These tools are not part of the main toolchain and maintained separately by thei
# Projects or Products that use Sigma
* [MISP](http://www.misp-project.org/2017/03/26/MISP.2.4.70.released.html) (since version 2.4.70, March 2017)
* [TA-Sigma-Searches](https://github.com/dstaulcu/TA-Sigma-Searches) (Splunk App)
* [SOC Prime - Sigma Rule Editor](https://tdm.socprime.com/sigma/)
* [ypsilon](https://github.com/P4T12ICK/ypsilon) - Automated Use Case Testing
* [uncoder.io](https://uncoder.io/) - Online Translator for SIEM Searches
* [SPARK](https://www.nextron-systems.com/2018/06/28/spark-applies-sigma-rules-in-eventlog-scan/) - Scan with Sigma rules on endpoints
* [THOR](https://www.nextron-systems.com/2018/06/28/spark-applies-sigma-rules-in-eventlog-scan/) - Scan with Sigma rules on endpoints
* [Joe Sandbox](https://www.joesecurity.org/)
* [ypsilon](https://github.com/P4T12ICK/ypsilon) - Automated Use Case Testing
* [RANK VASA](https://globenewswire.com/news-release/2019/03/04/1745907/0/en/RANK-Software-to-Help-MSSPs-Scale-Cybersecurity-Offerings.html)
* [TA-Sigma-Searches](https://github.com/dstaulcu/TA-Sigma-Searches) (Splunk App)
# Contribution
+1 -1
View File
@@ -9,7 +9,7 @@ logsource:
category: proxy
detection:
selection:
c-uri-query: '*/asp.asp?ui=*'
c-uri: '*/asp.asp?ui=*'
condition: selection
fields:
- ClientIP
+1 -1
View File
@@ -10,7 +10,7 @@ logsource:
category: proxy
detection:
selection:
c-uri-query: '*/list/suc?name=*'
c-uri: '*/list/suc?name=*'
condition: selection
fields:
- ClientIP
+25
View File
@@ -0,0 +1,25 @@
title: Crypto Miner User Agent
status: experimental
description: Detects suspicious user agent strings used by crypto miners in proxy logs
references:
- https://github.com/xmrig/xmrig/blob/da22b3e6c45825f3ac1f208255126cb8585cd4fc/src/base/kernel/Platform_win.cpp#L65
- https://github.com/xmrig/xmrig/blob/427b6516e0550200c17ca28675118f0fffcc323f/src/version.h
author: Florian Roth
date: 2019/10/21
logsource:
category: proxy
detection:
selection:
UserAgent:
# XMRig
- 'XMRig *'
# CCMiner
- 'ccminer*'
condition: selection
fields:
- ClientIP
- URL
- UserAgent
falsepositives:
- Unknown
level: high
+1 -1
View File
@@ -50,7 +50,7 @@ detection:
- 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/5.0)' # Fareit / Pony
- 'Mozilla/4.0 (compatible; MSIE 6.1; Windows NT)' # https://goo.gl/g43qjs
- 'Mozilla/4.0(compatible; MSIE 6.0; Windows NT 5.1)' # MacControl malware https://goo.gl/sqY3Ja https://www.symantec.com/connect/blogs/osxmacontrol-back-it-again
- 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)' # used by Zebrocy malware https://app.any.run/tasks/7d7fa4a0-6970-4428-828b-29572abf9ceb/
# Others
- '* pxyscand*'
- '* asd'
@@ -14,7 +14,8 @@ detection:
selection:
EventID: 4704
keywords:
- 'SeEnableDelegationPrivilege'
Message:
- '*SeEnableDelegationPrivilege*'
condition: all of them
falsepositives:
- Unknown
@@ -15,11 +15,13 @@ detection:
selection:
EventID: 4738
keywords:
- 'DES'
- 'Preauth'
- 'Encrypted'
Message:
- '*DES*'
- '*Preauth*'
- '*Encrypted*'
filters:
- 'Enabled'
Message:
- '*Enabled*'
condition: selection and keywords and filters
falsepositives:
- Unknown
@@ -14,6 +14,7 @@ logsource:
product: windows
detection:
keywords:
Message:
- "* mimikatz *"
- "* mimilib *"
- "* <3 eo.oe *"
+24 -22
View File
@@ -6,29 +6,31 @@ logsource:
service: application
detection:
keywords:
- HTool
- Hacktool
- ASP/Backdoor
- JSP/Backdoor
- PHP/Backdoor
- Backdoor.ASP
- Backdoor.JSP
- Backdoor.PHP
- Webshell
- Portscan
- Mimikatz
- WinCred
- PlugX
- Korplug
- Pwdump
- Chopper
- WmiExec
- Xscan
- Clearlog
- ASPXSpy
Message:
- "*HTool*"
- "*Hacktool*"
- "*ASP/Backdoor*"
- "*JSP/Backdoor*"
- "*PHP/Backdoor*"
- "*Backdoor.ASP*"
- "*Backdoor.JSP*"
- "*Backdoor.PHP*"
- "*Webshell*"
- "*Portscan*"
- "*Mimikatz*"
- "*WinCred*"
- "*PlugX*"
- "*Korplug*"
- "*Pwdump*"
- "*Chopper*"
- "*WmiExec*"
- "*Xscan*"
- "*Clearlog*"
- "*ASPXSpy*"
filters:
- Keygen
- Crack
Message:
- "*Keygen*"
- "*Crack*"
condition: keywords and not 1 of filters
falsepositives:
- Some software piracy tools (key generators, cracks) are classified as hack tools
+4 -3
View File
@@ -15,9 +15,10 @@ detection:
EventID:
- 7045
keywords:
- 'WCE SERVICE'
- 'WCESERVICE'
- 'DumpSvc'
Message:
- '*WCE SERVICE*'
- '*WCESERVICE*'
- '*DumpSvc*'
quarkspwdump:
EventID: 16
HiveName: '*\AppData\Local\Temp\SAM*.dmp'
@@ -25,4 +25,4 @@ detection:
condition: selection1 or (selection2 and not selection3)
falsepositives:
- Migration of an account into a new domain
level: medium
level: low
@@ -21,8 +21,9 @@ detection:
Source: 'Windows Error Reporting'
EventID: 1001
keywords:
- 'MsMpEng.exe'
- 'mpengine.dll'
Message:
- '*MsMpEng.exe*'
- '*mpengine.dll*'
condition: 1 of selection* and all of keywords
falsepositives:
- MsMpEng.exe can crash when C:\ is full
+2 -1
View File
@@ -13,7 +13,8 @@ detection:
selection:
EventID: 16
keywords:
- '*\AppData\Local\Temp\SAM-*.dmp *'
Message:
- '*\AppData\Local\Temp\SAM-*.dmp *'
condition: all of them
falsepositives:
- Penetration testing
+5 -4
View File
@@ -16,14 +16,15 @@ detection:
selection:
EventID: 5861
keywords:
- 'ActiveScriptEventConsumer'
- 'CommandLineEventConsumer'
- 'CommandLineTemplate'
Message:
- '*ActiveScriptEventConsumer*'
- '*CommandLineEventConsumer*'
- '*CommandLineTemplate*'
# - 'Binding EventFilter' # too many false positive with HP Health Driver
selection2:
EventID: 5859
condition: selection and 1 of keywords or selection2
falsepositives:
- Unknown (data set is too small; further testing needed)
level: high
level: medium
@@ -14,100 +14,101 @@ logsource:
definition: 'It is recommended to use the new "Script Block Logging" of PowerShell v5 https://adsecurity.org/?p=2277'
detection:
keywords:
- Invoke-DllInjection
- Invoke-Shellcode
- Invoke-WmiCommand
- Get-GPPPassword
- Get-Keystrokes
- Get-TimedScreenshot
- Get-VaultCredential
- Invoke-CredentialInjection
- Invoke-Mimikatz
- Invoke-NinjaCopy
- Invoke-TokenManipulation
- Out-Minidump
- VolumeShadowCopyTools
- Invoke-ReflectivePEInjection
- Invoke-UserHunter
- Find-GPOLocation
- Invoke-ACLScanner
- Invoke-DowngradeAccount
- Get-ServiceUnquoted
- Get-ServiceFilePermission
- Get-ServicePermission
- Invoke-ServiceAbuse
- Install-ServiceBinary
- Get-RegAutoLogon
- Get-VulnAutoRun
- Get-VulnSchTask
- Get-UnattendedInstallFile
- Get-ApplicationHost
- Get-RegAlwaysInstallElevated
- Get-Unconstrained
- Add-RegBackdoor
- Add-ScrnSaveBackdoor
- Gupt-Backdoor
- Invoke-ADSBackdoor
- Enabled-DuplicateToken
- Invoke-PsUaCme
- Remove-Update
- Check-VM
- Get-LSASecret
- Get-PassHashes
- Show-TargetScreen
- Port-Scan
- Invoke-PoshRatHttp
- Invoke-PowerShellTCP
- Invoke-PowerShellWMI
- Add-Exfiltration
- Add-Persistence
- Do-Exfiltration
- Start-CaptureServer
- Get-ChromeDump
- Get-ClipboardContents
- Get-FoxDump
- Get-IndexedItem
- Get-Screenshot
- Invoke-Inveigh
- Invoke-NetRipper
- Invoke-EgressCheck
- Invoke-PostExfil
- Invoke-PSInject
- Invoke-RunAs
- MailRaider
- New-HoneyHash
- Set-MacAttribute
- Invoke-DCSync
- Invoke-PowerDump
- Exploit-Jboss
- Invoke-ThunderStruck
- Invoke-VoiceTroll
- Set-Wallpaper
- Invoke-InveighRelay
- Invoke-PsExec
- Invoke-SSHCommand
- Get-SecurityPackages
- Install-SSP
- Invoke-BackdoorLNK
- PowerBreach
- Get-SiteListPassword
- Get-System
- Invoke-BypassUAC
- Invoke-Tater
- Invoke-WScriptBypassUAC
- PowerUp
- PowerView
- Get-RickAstley
- Find-Fruit
- HTTP-Login
- Find-TrustedDocuments
- Invoke-Paranoia
- Invoke-WinEnum
- Invoke-ARPScan
- Invoke-PortScan
- Invoke-ReverseDNSLookup
- Invoke-SMBScanner
- Invoke-Mimikittenz
Message:
- "*Invoke-DllInjection*"
- "*Invoke-Shellcode*"
- "*Invoke-WmiCommand*"
- "*Get-GPPPassword*"
- "*Get-Keystrokes*"
- "*Get-TimedScreenshot*"
- "*Get-VaultCredential*"
- "*Invoke-CredentialInjection*"
- "*Invoke-Mimikatz*"
- "*Invoke-NinjaCopy*"
- "*Invoke-TokenManipulation*"
- "*Out-Minidump*"
- "*VolumeShadowCopyTools*"
- "*Invoke-ReflectivePEInjection*"
- "*Invoke-UserHunter*"
- "*Find-GPOLocation*"
- "*Invoke-ACLScanner*"
- "*Invoke-DowngradeAccount*"
- "*Get-ServiceUnquoted*"
- "*Get-ServiceFilePermission*"
- "*Get-ServicePermission*"
- "*Invoke-ServiceAbuse*"
- "*Install-ServiceBinary*"
- "*Get-RegAutoLogon*"
- "*Get-VulnAutoRun*"
- "*Get-VulnSchTask*"
- "*Get-UnattendedInstallFile*"
- "*Get-ApplicationHost*"
- "*Get-RegAlwaysInstallElevated*"
- "*Get-Unconstrained*"
- "*Add-RegBackdoor*"
- "*Add-ScrnSaveBackdoor*"
- "*Gupt-Backdoor*"
- "*Invoke-ADSBackdoor*"
- "*Enabled-DuplicateToken*"
- "*Invoke-PsUaCme*"
- "*Remove-Update*"
- "*Check-VM*"
- "*Get-LSASecret*"
- "*Get-PassHashes*"
- "*Show-TargetScreen*"
- "*Port-Scan*"
- "*Invoke-PoshRatHttp*"
- "*Invoke-PowerShellTCP*"
- "*Invoke-PowerShellWMI*"
- "*Add-Exfiltration*"
- "*Add-Persistence*"
- "*Do-Exfiltration*"
- "*Start-CaptureServer*"
- "*Get-ChromeDump*"
- "*Get-ClipboardContents*"
- "*Get-FoxDump*"
- "*Get-IndexedItem*"
- "*Get-Screenshot*"
- "*Invoke-Inveigh*"
- "*Invoke-NetRipper*"
- "*Invoke-EgressCheck*"
- "*Invoke-PostExfil*"
- "*Invoke-PSInject*"
- "*Invoke-RunAs*"
- "*MailRaider*"
- "*New-HoneyHash*"
- "*Set-MacAttribute*"
- "*Invoke-DCSync*"
- "*Invoke-PowerDump*"
- "*Exploit-Jboss*"
- "*Invoke-ThunderStruck*"
- "*Invoke-VoiceTroll*"
- "*Set-Wallpaper*"
- "*Invoke-InveighRelay*"
- "*Invoke-PsExec*"
- "*Invoke-SSHCommand*"
- "*Get-SecurityPackages*"
- "*Install-SSP*"
- "*Invoke-BackdoorLNK*"
- "*PowerBreach*"
- "*Get-SiteListPassword*"
- "*Get-System*"
- "*Invoke-BypassUAC*"
- "*Invoke-Tater*"
- "*Invoke-WScriptBypassUAC*"
- "*PowerUp*"
- "*PowerView*"
- "*Get-RickAstley*"
- "*Find-Fruit*"
- "*HTTP-Login*"
- "*Find-TrustedDocuments*"
- "*Invoke-Paranoia*"
- "*Invoke-WinEnum*"
- "*Invoke-ARPScan*"
- "*Invoke-PortScan*"
- "*Invoke-ReverseDNSLookup*"
- "*Invoke-SMBScanner*"
- "*Invoke-Mimikittenz*"
false_positives:
- Get-SystemDriveInfo # http://bheltborg.dk/Windows/WinSxS/amd64_microsoft-windows-maintenancediagnostic_31bf3856ad364e35_10.0.10240.16384_none_91ef7543a4514b5e/CL_Utility.ps1
condition: keywords and not false_positives
@@ -14,26 +14,27 @@ logsource:
definition: 'It is recommended to use the new "Script Block Logging" of PowerShell v5 https://adsecurity.org/?p=2277'
detection:
keywords:
- AdjustTokenPrivileges
- IMAGE_NT_OPTIONAL_HDR64_MAGIC
- Microsoft.Win32.UnsafeNativeMethods
- ReadProcessMemory.Invoke
- SE_PRIVILEGE_ENABLED
- LSA_UNICODE_STRING
- MiniDumpWriteDump
- PAGE_EXECUTE_READ
- SECURITY_DELEGATION
- TOKEN_ADJUST_PRIVILEGES
- TOKEN_ALL_ACCESS
- TOKEN_ASSIGN_PRIMARY
- TOKEN_DUPLICATE
- TOKEN_ELEVATION
- TOKEN_IMPERSONATE
- TOKEN_INFORMATION_CLASS
- TOKEN_PRIVILEGES
- TOKEN_QUERY
- Metasploit
- Mimikatz
Message:
- "*AdjustTokenPrivileges*"
- "*IMAGE_NT_OPTIONAL_HDR64_MAGIC*"
- "*Microsoft.Win32.UnsafeNativeMethods*"
- "*ReadProcessMemory.Invoke*"
- "*SE_PRIVILEGE_ENABLED*"
- "*LSA_UNICODE_STRING*"
- "*MiniDumpWriteDump*"
- "*PAGE_EXECUTE_READ*"
- "*SECURITY_DELEGATION*"
- "*TOKEN_ADJUST_PRIVILEGES*"
- "*TOKEN_ALL_ACCESS*"
- "*TOKEN_ASSIGN_PRIMARY*"
- "*TOKEN_DUPLICATE*"
- "*TOKEN_ELEVATION*"
- "*TOKEN_IMPERSONATE*"
- "*TOKEN_INFORMATION_CLASS*"
- "*TOKEN_PRIVILEGES*"
- "*TOKEN_QUERY*"
- "*Metasploit*"
- "*Mimikatz*"
condition: keywords
falsepositives:
- Penetration tests
@@ -17,7 +17,8 @@ detection:
selection:
EventID: 4104
keyword:
- 'PromptForCredential'
Message:
- '*PromptForCredential*'
condition: all of them
falsepositives:
- Unknown
@@ -10,8 +10,9 @@ logsource:
service: powershell
detection:
keywords:
- 'System.Net.WebClient).DownloadString('
- 'system.net.webclient).downloadfile('
Message:
- '*System.Net.WebClient).DownloadString(*'
- '*system.net.webclient).downloadfile(*'
condition: keywords
falsepositives:
- PowerShell scripts that download content from the Internet
@@ -10,12 +10,13 @@ logsource:
service: powershell
detection:
keywords:
- ' -nop -w hidden -c * [Convert]::FromBase64String'
- ' -w hidden -noni -nop -c "iex(New-Object'
- ' -w hidden -ep bypass -Enc'
- 'powershell.exe reg add HKCU\software\microsoft\windows\currentversion\run'
- 'bypass -noprofile -windowstyle hidden (new-object system.net.webclient).download'
- 'iex(New-Object Net.WebClient).Download'
Message:
- '* -nop -w hidden -c * [Convert]::FromBase64String*'
- '* -w hidden -noni -nop -c "iex(New-Object*'
- '* -w hidden -ep bypass -Enc*'
- '*powershell.exe reg add HKCU\software\microsoft\windows\currentversion\run*'
- '*bypass -noprofile -windowstyle hidden (new-object system.net.webclient).download*'
- '*iex(New-Object Net.WebClient).Download*'
condition: keywords
falsepositives:
- Penetration tests
@@ -14,7 +14,8 @@ logsource:
definition: 'It is recommended to use the new "Script Block Logging" of PowerShell v5 https://adsecurity.org/?p=2277'
detection:
keywords:
- System.Reflection.Assembly.Load
Message:
- "*[System.Reflection.Assembly]::Load*"
condition: keywords
falsepositives:
- Penetration tests
@@ -0,0 +1,30 @@
title: Mustang Panda Dropper
status: experimental
description: Detects specific process parameters as used by Mustang Panda droppers
author: Florian Roth
date: 2019/10/30
references:
- https://app.any.run/tasks/7ca5661d-a67b-43ec-98c1-dd7a8103c256/
- https://app.any.run/tasks/b12cccf3-1c22-4e28-9d3e-c7a6062f3914/
- https://www.anomali.com/blog/china-based-apt-mustang-panda-targets-minority-groups-public-and-private-sector-organizations
logsource:
category: process_creation
product: windows
detection:
selection1:
CommandLine:
- '*Temp\wtask.exe /create*'
- '*%windir:~-3,1%%PUBLIC:~-9,1%*'
- '*/E:vbscript * C:\Users\*.txt" /F'
- '*/tn "Security Script *'
- '*%windir:~-1,1%*'
selection2:
Image:
- '*Temp\winwsh.exe'
condition: 1 of them
fields:
- CommandLine
- ParentCommandLine
falsepositives:
- Unlikely
level: high
@@ -0,0 +1,30 @@
title: Suspicious HWP Sub Processes
description: Detects suspicious Hangul Word Processor (Hanword) sub processes that could indicate an exploitation
status: experimental
references:
- https://www.securitynewspaper.com/2016/11/23/technical-teardown-exploit-malware-hwp-files/
- https://www.hybrid-analysis.com/search?query=context:74940dcc5b38f9f9b1a0fea760d344735d7d91b610e6d5bd34533dd0153402c5&from_sample=5db135000388385a7644131f&block_redirect=1
- https://twitter.com/cyberwar_15/status/1187287262054076416
- https://blog.alyac.co.kr/1901
- https://en.wikipedia.org/wiki/Hangul_(word_processor)
tags:
- attack.execution
- attack.defense_evasion
- attack.initial_access
- attack.t1059
- attack.t1202
- attack.t1193
- attack.g0032
author: Florian Roth
date: 2019/10/24
logsource:
category: process_creation
product: windows
detection:
selection:
ParentImage: '*\Hwp.exe'
Image: '*\gbb.exe'
condition: selection
falsepositives:
- Unknown
level: high
@@ -0,0 +1,22 @@
title: DTRACK Process Creation
status: experimental
description: Detects specific process parameters as seen in DTRACK infections
author: Florian Roth
date: 2019/10/30
references:
- https://securelist.com/my-name-is-dtrack/93338/
- https://app.any.run/tasks/4bc9860d-ab51-4077-9e09-59ad346b92fd/
- https://app.any.run/tasks/ce4deab5-3263-494f-93e3-afb2b9d79f14/
logsource:
category: process_creation
product: windows
detection:
selection:
CommandLine: '* echo EEEE > *'
condition: selection
fields:
- CommandLine
- ParentCommandLine
falsepositives:
- Unlikely
level: critical
@@ -3,10 +3,12 @@ status: experimental
description: Detects Formbook like process executions that inject code into a set of files in the System32 folder, which executes a special command command line to delete the dropper from the AppData Temp folder. We avoid false positives by excluding all parent process with command line parameters.
author: Florian Roth
date: 2019/09/30
modified: 2019/10/31
references:
- https://inquest.net/blog/2018/06/22/a-look-at-formbook-stealer
- https://app.any.run/tasks/388d5802-aa48-4826-b069-250420504758/
- https://app.any.run/tasks/8e22486b-5edc-4cef-821c-373e945f296c/
- https://app.any.run/tasks/62bb01ae-25a4-4180-b278-8e464a90b8d7/
logsource:
category: process_creation
product: windows
@@ -15,10 +17,13 @@ detection:
# Parent command line should not contain a space value
# This avoids false positives not caused by process injection
# e.g. wscript.exe /B sysmon-install.vbs
ParentCommandLine: 'C:\Windows\System32\\*.exe'
ParentCommandLine:
- 'C:\Windows\System32\\*.exe'
- 'C:\Windows\SysWOW64\\*.exe'
CommandLine:
- '*\cmd.exe /c del "C:\Users\\*\AppData\Local\Temp\\*.exe'
- '*\cmd.exe /c del "C:\Users\\*\Desktop\\*.exe'
- '* /c del "C:\Users\\*\AppData\Local\Temp\\*.exe'
- '* /c del "C:\Users\\*\Desktop\\*.exe'
- '* /C type nul > "C:\Users\\*\Desktop\\*.exe'
condition: selection
fields:
- CommandLine
@@ -36,7 +36,7 @@ detection:
- '*\schtasks.exe'
- '*\regsvr32.exe'
- '*\hh.exe'
- '*\wmic.exe'
- '*\wmic.exe' # https://app.any.run/tasks/c903e9c8-0350-440c-8688-3881b556b8e0/
- '*\mshta.exe'
- '*\rundll32.exe'
- '*\msiexec.exe'
@@ -21,7 +21,7 @@ detection:
- '*\installutil.exe*'
- '*\regsvcs.exe*'
- '*\regasm.exe*'
- '*\regsvr32.exe*'
# - '*\regsvr32.exe*' # too many FPs, very noisy
- '*\msbuild.exe*'
- '*\ieexec.exe*'
- '*\mshta.exe*'
@@ -8,6 +8,7 @@ references:
- https://www.13cubed.com/downloads/windows_process_genealogy_v2.pdf
- https://attack.mitre.org/techniques/T1036/
date: 2019/02/23
modified: 2019/08/20
tags:
- attack.defense_evasion
- attack.t1036
@@ -18,7 +18,7 @@ detection:
ParentImage:
- '*\mshta.exe'
- '*\powershell.exe'
- '*\cmd.exe'
# - '*\cmd.exe' # too many false positives
- '*\rundll32.exe'
- '*\cscript.exe'
- '*\wscript.exe'
@@ -0,0 +1,22 @@
title: Firewall Disabled via Netsh
description: Detects netsh commands that turns off the Windows firewall
references:
- https://www.winhelponline.com/blog/enable-and-disable-windows-firewall-quickly-using-command-line/
- https://app.any.run/tasks/210244b9-0b6b-4a2c-83a3-04bd3175d017/
date: 2019/11/01
status: experimental
author: Fatih Sirin
tags:
- attack.defense_evasion
logsource:
category: process_creation
product: windows
detection:
selection:
CommandLine:
- netsh firewall set opmode mode=disable
- netsh advfirewall set * state off
condition: selection
falsepositives:
- Legitimate administration
level: medium
@@ -14,7 +14,7 @@ logsource:
detection:
selection:
CommandLine:
- '* msiexec*:\/\/*'
- '* msiexec*://*'
condition: selection
falsepositives:
- False positives depend on scripts and administrative tools used in the monitored environment
@@ -0,0 +1,24 @@
title: Suspicious Call by Ordinal
description: Detects suspicious calls of DLLs in rundll32.dll exports by ordinal
status: experimental
references:
- https://techtalk.pcmatic.com/2017/11/30/running-dll-files-malware-analysis/
- https://github.com/Neo23x0/DLLRunner
- https://twitter.com/cyb3rops/status/1186631731543236608
tags:
- attack.defense_evasion
- attack.execution
- attack.t1085
author: Florian Roth
date: 2019/10/22
logsource:
category: process_creation
product: windows
detection:
selection:
CommandLine: '*\rundll32.exe *,#*'
condition: selection
falsepositives:
- False positives depend on scripts and administrative tools used in the monitored environment
- Windows contol panel elements have been identified as source (mmc)
level: high
@@ -3,6 +3,7 @@ status: experimental
description: Detects Possible Squirrel Packages Manager as Lolbin
references:
- http://www.hexacorn.com/blog/2019/03/30/sqirrel-packages-manager-as-a-lolbin-a-k-a-many-electron-apps-are-lolbins-by-default/
- http://www.hexacorn.com/blog/2018/08/16/squirrel-as-a-lolbin/
tags:
- attack.execution
author: Karneades / Markus Neis
@@ -49,7 +50,8 @@ detection:
- '*\update.exe' # Check if folder Name matches executed binary \\(?P<first>[^\\]*)\\Update.*Start.{2}(?P<second>\1)\.exe (example: https://regex101.com/r/SGSQGz/2)
CommandLine:
- '*--processStart*.exe*'
- '*--processStartAndWait*.exe*'
- '*createShortcut*.exe*'
condition: selection
@@ -1,6 +1,6 @@
title: Suspicious Userinit Child Process
status: experimental
description: Detects the creation of a process from Windows task manager
description: Detects a suspicious child process of userinit
references:
- https://twitter.com/SBousseaden/status/1139811587760562176
author: Florian Roth (rule), Samir Bousseaden (idea)
@@ -11,14 +11,14 @@ logsource:
detection:
selection:
ParentImage: '*\userinit.exe'
filter:
CommandLine:
- '*\explorer.exe*'
- '*\\netlogon\\*'
condition: selection and not filter
filter1:
CommandLine: '*\\netlogon\\*'
filter2:
Image: '*\explorer.exe'
condition: selection and not filter1 and not filter2
fields:
- CommandLine
- ParentCommandLine
falsepositives:
- Administrative scripts
level: high
level: medium
@@ -1,6 +1,14 @@
title: Webshell Detection With Command Line Keywords
description: Detects certain command line parameters often used during reconnaissance activity via web shells
author: Florian Roth
reference:
- https://www.fireeye.com/blog/threat-research/2013/08/breaking-down-the-china-chopper-web-shell-part-ii.html
date: 2017/01/01
modified: 2019/10/26
tags:
- attack.privilege_escalation
- attack.persistence
- attack.t1100
logsource:
category: process_creation
product: windows
@@ -14,18 +22,16 @@ detection:
- '*\nginx.exe'
- '*\httpd.exe'
CommandLine:
- whoami
- net user
- ping -n
- systeminfo
- '*whoami*'
- '*net user *'
- '*ping -n *'
- '*systeminfo'
- '*&cd&echo*'
- '*cd /d*' # https://www.computerhope.com/cdhlp.htm
condition: selection
fields:
- CommandLine
- ParentCommandLine
tags:
- attack.privilege_escalation
- attack.persistence
- attack.t1100
falsepositives:
- unknown
level: high
@@ -15,20 +15,27 @@ detection:
exec_selection:
EventID: 1 # Migration to process_creation requires multipart YAML
ParentImage: '*\userinit.exe'
exec_exclusion:
exec_exclusion1:
Image: '*\explorer.exe'
exec_exclusion2:
CommandLine: '*\netlogon.bat'
create_selection:
create_selection_cli:
EventID:
- 1
create_selection_reg:
EventID:
- 11
- 12
- 13
- 14
create_keywords:
- UserInitMprLogonScript
condition: (exec_selection and not exec_exclusion) or (create_selection and create_keywords)
create_keywords_reg:
TargetObject:
- '*UserInitMprLogonScript*'
create_keywords_cli:
CommandLine:
- '*UserInitMprLogonScript*'
condition: (exec_selection and not exec_exclusion1 and not exec_exclusion2) or (create_selection_reg and create_keywords_reg) or (create_selection_cli and create_keywords_cli)
falsepositives:
- exclude legitimate logon scripts
- penetration tests, red teaming
level: high
level: high
@@ -6,6 +6,7 @@ references:
- https://www.virustotal.com/#/file/276a765a10f98cda1a38d3a31e7483585ca3722ecad19d784441293acf1b7beb/detection
author: Markus Neis
date: 2018/11/22
modified: 2019/11/09
tags:
- attack.defense_evasion
- attack.execution
@@ -29,4 +30,4 @@ fields:
- ParentCommandLine
falsepositives:
- Unknown
level: high
level: medium
@@ -0,0 +1,35 @@
title: Svchost DLL Search Order Hijack
status: experimental
description: IKEEXT and SessionEnv service, as they call LoadLibrary on files that do not exist within C:\Windows\System32\ by default. An attacker can place their malicious logic within the PROCESS_ATTACH block of their library and restart the aforementioned services "svchost.exe -k netsvcs" to gain code execution on a remote machine.
references:
- https://posts.specterops.io/lateral-movement-scm-and-dll-hijacking-primer-d2f61e8ab992
author: SBousseaden
date: 2019/10/28
tags:
- attack.persistence
- attack.defense_evasion
- attack.t1073
- attack.t1038
- attack.t1112
logsource:
product: windows
service: sysmon
detection:
selection:
EventID: 7
Image:
- '*\svchost.exe'
ImageLoaded:
- '*\tsmsisrv.dll'
- '*\tsvipsrv.dll'
- '*\wlbsctrl.dll'
filter:
EventID: 7
Image:
- '*\svchost.exe'
ImageLoaded:
- 'C:\Windows\WinSxS\*'
condition: selection and not filter
falsepositives:
- Pentest
level: high
+2
View File
@@ -13,4 +13,6 @@ detection:
- foo
- bar
- bla
end|endswith: test
start|startswith: test
condition: selection
-1
View File
@@ -12,4 +12,3 @@ logsources:
fieldmappings:
Image: NewProcessName
ParentImage: ParentProcessName
CommandLine: ProcessCommandLine
+11
View File
@@ -0,0 +1,11 @@
title: LimaCharlie
backends:
- limacharlie
order: 20
logsources:
windows:
product: windows
linux:
product: linux
netflow:
product: netflow
+4 -2
View File
@@ -13,7 +13,7 @@ with open(path.join(here, 'README.md'), encoding='utf-8') as f:
setup(
name='sigmatools',
version='0.13',
version='0.14',
description='Tools for the Generic Signature Format for SIEM Systems',
long_description=long_description,
long_description_content_type="text/markdown",
@@ -36,7 +36,7 @@ setup(
keywords='security monitoring siem logging signatures elasticsearch splunk ids sysmon',
packages=['sigma', 'sigma.backends', 'sigma.config', 'sigma.parser', 'sigma.parser.modifiers'],
python_requires='~=3.6',
install_requires=['PyYAML', 'pymisp'],
install_requires=['PyYAML', 'pymisp', 'progressbar2'],
extras_require={
'test': ['coverage', 'yamllint'],
},
@@ -60,6 +60,7 @@ setup(
'config/winlogbeat-modules-enabled.yml',
'config/winlogbeat.yml',
'config/winlogbeat-old.yml',
'config/limacharlie.yml',
]),
('etc/sigma/generic', [
'config/generic/sysmon.yml',
@@ -69,5 +70,6 @@ setup(
'sigmac',
'merge_sigma',
'sigma2misp',
'sigma-similarity',
]
)
+91
View File
@@ -0,0 +1,91 @@
#!/usr/bin/env python3
# Calculates similarity of Sigma rules by transformation into a normalized
# string form and calculation of a string distance.
import argparse
import pathlib
import itertools
import difflib
import progressbar
from sigma.parser.collection import SigmaCollectionParser
from sigma.backends.base import SingleTextQueryBackend
from sigma.configuration import SigmaConfiguration
argparser = argparse.ArgumentParser(description="Calculate a similarity score between Sigma rules.")
argparser.add_argument("--recursive", "-r", action="store_true", help="Recurse into directories")
argparser.add_argument("--verbose", "-v", action="count", help="Be verbose. Use once more for debug output.")
argparser.add_argument("--top", "-t", type=int, help="Only output the n most similar rule pairs.")
argparser.add_argument("--min-similarity", "-m", type=int, help="Only output pairs with a similarity above this threshold (percent)")
argparser.add_argument("inputs", nargs="+", help="Sigma input files")
args = argparser.parse_args()
def print_verbose(level, *args, **kwargs):
if args.verbose >= level:
print(*args, **kwargs)
class SigmaNormalizationBackend(SingleTextQueryBackend):
"""Normalization of a Sigma rule into a non-existing query language that supports all Sigma features"""
andToken = " AND "
orToken = " OR "
notToken = " NOT "
subExpression = "(%s)"
listExpression = "[%s]"
listSeparator = ","
valueExpression = "%s"
typedValueExpression = dict()
nullExpression = "NULL(%s)"
notNullExpression = "NOTNULL(%s)"
mapExpression = "{'%s':'%s'}"
sort_condition_lists = True
def generateListNode(self, node):
"""Return sorted list"""
return super().generateListNode(list(sorted([ str(item) for item in node ])))
def generateTypedValueNode(self, node):
"""Return normalized form of typed values"""
return "type_{}({})".format(node.identifier, str(node))
def generateAggregation(self, agg):
if agg.aggfunc_notrans == "near":
return " near in={} ex={}".format(str(agg.include), str(agg.exclude))
else:
return " | {}({}) by {} {} {}".format(agg.aggfunc_notrans, agg.aggfield, agg.groupfield, agg.cond_op, agg.condition)
backend = SigmaNormalizationBackend(SigmaConfiguration())
if args.recursive:
paths = [ p for pathname in args.inputs for p in pathlib.Path(pathname).glob("**/*") if p.is_file() ]
else:
paths = [ pathlib.Path(pathname) for pathname in args.inputs ]
parsed = {
str(path): SigmaCollectionParser(path.open().read())
for path in paths
}
converted = {
str(path): list(sigma_collection.generate(backend))
for path, sigma_collection in parsed.items()
}
converted_flat = (
(path, i, normalized)
for path, nlist in converted.items()
for i, normalized in zip(range(len(nlist)), nlist)
)
converted_pairs = list(itertools.combinations(converted_flat, 2))
similarities = [
(item1[:2], item2[:2], difflib.SequenceMatcher(None, item1[2], item2[2]).ratio())
for item1, item2 in progressbar.progressbar(converted_pairs)
]
i = 0
for similarity in sorted(similarities, key=lambda s: s[2], reverse=True):
if args.min_similarity and similarity[2] * 100 < args.min_similarity: # finish after similarity drops below minimum
break
print("{:70} | {:2} | {:70} | {:2} | {:>3.2%}".format(*similarity[0], *similarity[1], similarity[2]))
i += 1
if args.top and i >= args.top: # end after $top pairs
break
+8 -1
View File
@@ -89,8 +89,9 @@ class BaseBackend:
file_list = None
options = tuple() # a list of tuples with following elements: option name, default value, help text, target attribute name (option name if None)
config_required = True
default_config = None
def __init__(self, sigmaconfig, backend_options=None):
def __init__(self, sigmaconfig, backend_options=dict()):
"""
Initialize backend. This gets a sigmaconfig object, which is notified about the used backend class by
passing the object instance to it.
@@ -221,10 +222,14 @@ class SingleTextQueryBackend(RulenameCommentMixin, BaseBackend, QuoteCharMixin):
mapListsSpecialHandling = False # Same handling for map items with list values as for normal values (strings, integers) if True, generateMapItemListNode method is called with node
mapListValueExpression = None # Syntax for field/value condititons where map value is a list
sort_condition_lists = False # Sort condition items for AND and OR conditions
def generateANDNode(self, node):
generated = [ self.generateNode(val) for val in node ]
filtered = [ g for g in generated if g is not None ]
if filtered:
if self.sort_condition_lists:
filtered = sorted(filtered)
return self.andToken.join(filtered)
else:
return None
@@ -233,6 +238,8 @@ class SingleTextQueryBackend(RulenameCommentMixin, BaseBackend, QuoteCharMixin):
generated = [ self.generateNode(val) for val in node ]
filtered = [ g for g in generated if g is not None ]
if filtered:
if self.sort_condition_lists:
filtered = sorted(filtered)
return self.orToken.join(filtered)
else:
return None
+31 -4
View File
@@ -22,6 +22,7 @@ import sys
import sigma
import yaml
from sigma.parser.modifiers.type import SigmaRegularExpressionModifier
from sigma.parser.condition import ConditionOR, ConditionAND, NodeSubexpression
from .base import BaseBackend, SingleTextQueryBackend
from .mixins import RulenameCommentMixin, MultiRuleOutputMixin
from .exceptions import NotSupportedError
@@ -109,6 +110,29 @@ class ElasticsearchQuerystringBackend(ElasticsearchWildcardHandlingMixin, Single
if expression:
return "(%s%s)" % (self.notToken, expression)
def generateSubexpressionNode(self, node):
"""Check for search not bound to a field and restrict search to keyword fields"""
nodetype = type(node.items)
if nodetype in { ConditionAND, ConditionOR } and type(node.items.items) == list and { type(item) for item in node.items.items }.issubset({str, int}):
newitems = list()
for item in node.items:
newitem = item
if type(item) == str:
if not item.startswith("*"):
newitem = "*" + newitem
if not item.endswith("*"):
newitem += "*"
newitems.append(newitem)
else:
newitems.append(item)
newnode = NodeSubexpression(nodetype(None, None, *newitems))
self.matchKeyword = True
result = "\\*.keyword:" + super().generateSubexpressionNode(newnode)
self.matchKeyword = False # one of the reasons why the converter needs some major overhaul
return result
else:
return super().generateSubexpressionNode(node)
class ElasticsearchDSLBackend(RulenameCommentMixin, ElasticsearchWildcardHandlingMixin, BaseBackend):
"""ElasticSearch DSL backend"""
identifier = 'es-dsl'
@@ -188,8 +212,6 @@ class ElasticsearchDSLBackend(RulenameCommentMixin, ElasticsearchWildcardHandlin
def generateMapItemNode(self, node):
key, value = node
if type(value) not in (str, int, list, type(None)):
raise TypeError("Map values must be strings, numbers, lists or null, not " + str(type(value)))
if type(value) is list:
res = {'bool': {'should': []}}
for v in value:
@@ -206,7 +228,7 @@ class ElasticsearchDSLBackend(RulenameCommentMixin, ElasticsearchWildcardHandlin
elif value is None:
key_mapped = self.fieldNameMapping(key, value)
return { "bool": { "must_not": { "exists": { "field": key_mapped } } } }
else:
elif type(value) in (str, int):
key_mapped = self.fieldNameMapping(key, value)
if self.matchKeyword: # searches against keyowrd fields are wildcard searches, phrases otherwise
queryType = 'wildcard'
@@ -215,6 +237,11 @@ class ElasticsearchDSLBackend(RulenameCommentMixin, ElasticsearchWildcardHandlin
queryType = 'match_phrase'
value_cleaned = self.cleanValue(str(value))
return {queryType: {key_mapped: value_cleaned}}
elif isinstance(value, SigmaRegularExpressionModifier):
key_mapped = self.fieldNameMapping(key, value)
return { 'regexp': { key_mapped: str(value) } }
else:
raise TypeError("Map values must be strings, numbers, lists, null or regular expression, not " + str(type(value)))
def generateValueNode(self, node):
return {'multi_match': {'query': node, 'fields': [], 'type': 'phrase'}}
@@ -888,7 +915,7 @@ class ElastalertBackend(MultiRuleOutputMixin):
def finalize(self):
result = ""
for rulename, rule in self.elastalert_alerts.items():
result += yaml.dump(rule, default_flow_style=False)
result += yaml.dump(rule, default_flow_style=False, width=10000)
result += '\n'
return result
+2 -13
View File
@@ -15,24 +15,13 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import re
from .base import SingleTextQueryBackend
from .elasticsearch import ElasticsearchQuerystringBackend
class GraylogQuerystringBackend(SingleTextQueryBackend):
class GraylogQuerystringBackend(ElasticsearchQuerystringBackend):
"""Converts Sigma rule into Graylog query string. Only searches, no aggregations."""
identifier = "graylog"
active = True
config_required = False
reEscape = re.compile("([+\\-!(){}\\[\\]^\"~:/]|(?<!\\\\)\\\\(?![*?\\\\])|&&|\\|\\|)")
reClear = None
andToken = " AND "
orToken = " OR "
notToken = "NOT "
subExpression = "(%s)"
listExpression = "(%s)"
listSeparator = " "
valueExpression = "\"%s\""
nullExpression = "NOT _exists_:%s"
notNullExpression = "_exists_:%s"
mapExpression = "%s:%s"
mapListsSpecialHandling = False
+587
View File
@@ -0,0 +1,587 @@
# LimaCharlie backend for sigmac created by LimaCharlie.io
# Copyright 2019 Refraction Point, Inc
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import re
import yaml
from collections import namedtuple
from .base import BaseBackend
from sigma.parser.modifiers.base import SigmaTypeModifier
from sigma.parser.modifiers.type import SigmaRegularExpressionModifier
# A few helper functions for cases where field mapping cannot be done
# as easily one by one, or can be done more efficiently.
def _windowsEventLogFieldName(fieldName):
if 'EventID' == fieldName:
return 'Event/System/EventID'
return 'Event/EventData/%s' % (fieldName,)
def _mapProcessCreationOperations(node):
# Here we fix some common pitfalls found in rules
# in a consistent fashion (already processed to D&R rule).
# First fixup is looking for a specific path prefix
# based on a specific drive letter. There are many cases
# where the driver letter can change or where the early
# boot process refers to it as "\Device\HarddiskVolume1\".
if ("starts with" == node["op"] and
"event/FILE_PATH" == node["path"] and
node["value"].lower().startswith("c:\\")):
node["op"] = "matches"
node["re"] = "^(?:(?:.:)|(?:\\\\Device\\\\HarddiskVolume.))\\\\%s" % (re.escape(node["value"][3:]),)
del(node["value"])
return node
# We support many different log sources so we keep different mapping depending
# on the log source and category.
# The mapping key is product/category/service.
# The mapping value is tuple like:
# - top-level parameters
# - pre-condition is a D&R rule node filtering relevant events.
# - field mappings is a dict with a mapping or a callable to convert the field name.
# Individual mapping values can also be callabled(fieldname, value) returning a new fieldname and value.
# - isAllStringValues is a bool indicating whether all values should be converted to string.
# - keywordField is the field name to alias for keywords if supported or None if not.
# - postOpMapper is a callback that can modify an operation once it has been generated.
SigmaLCConfig = namedtuple('SigmaLCConfig', [
'topLevelParams',
'preConditions',
'fieldMappings',
'isAllStringValues',
'keywordField',
'postOpMapper',
])
_allFieldMappings = {
"windows/process_creation/": SigmaLCConfig(
topLevelParams = {
"events": [
"NEW_PROCESS",
"EXISTING_PROCESS",
]
},
preConditions = {
"op": "is windows",
},
fieldMappings = {
"CommandLine": "event/COMMAND_LINE",
"Image": "event/FILE_PATH",
"ParentImage": "event/PARENT/FILE_PATH",
"ParentCommandLine": "event/PARENT/COMMAND_LINE",
"User": "event/USER_NAME",
# This field is redundant in LC, it seems to always be used with Image
# so we will ignore it.
"OriginalFileName": lambda fn, fv: ("event/FILE_PATH", "*" + fv),
# Custom field names coming from somewhere unknown.
"NewProcessName": "event/FILE_PATH",
"ProcessCommandLine": "event/COMMAND_LINE",
# Another one-off command line.
"Command": "event/COMMAND_LINE",
},
isAllStringValues = False,
keywordField = "event/COMMAND_LINE",
postOpMapper = _mapProcessCreationOperations
),
"windows//": SigmaLCConfig(
topLevelParams = {
"target": "log",
"log type": "wel",
},
preConditions = None,
fieldMappings = _windowsEventLogFieldName,
isAllStringValues = True,
keywordField = None,
postOpMapper = None
),
"windows_defender//": SigmaLCConfig(
topLevelParams = {
"target": "log",
"log type": "wel",
},
preConditions = None,
fieldMappings = _windowsEventLogFieldName,
isAllStringValues = True,
keywordField = None,
postOpMapper = None
),
"dns//": SigmaLCConfig(
topLevelParams = {
"event": "DNS_REQUEST",
},
preConditions = None,
fieldMappings = {
"query": "event/DOMAIN_NAME",
},
isAllStringValues = False,
keywordField = None,
postOpMapper = None
),
"linux//": SigmaLCConfig(
topLevelParams = {
"events": [
"NEW_PROCESS",
"EXISTING_PROCESS",
]
},
preConditions = {
"op": "is linux",
},
fieldMappings = {
"exe": "event/FILE_PATH",
"type": None,
},
isAllStringValues = False,
keywordField = 'event/COMMAND_LINE',
postOpMapper = None
),
"unix//": SigmaLCConfig(
topLevelParams = {
"events": [
"NEW_PROCESS",
"EXISTING_PROCESS",
]
},
preConditions = {
"op": "is linux",
},
fieldMappings = {
"exe": "event/FILE_PATH",
"type": None,
},
isAllStringValues = False,
keywordField = 'event/COMMAND_LINE',
postOpMapper = None
),
"netflow//": SigmaLCConfig(
topLevelParams = {
"event": "NETWORK_CONNECTIONS",
},
preConditions = None,
fieldMappings = {
"destination.port": "event/NETWORK_ACTIVITY/DESTINATION/PORT",
"source.port": "event/NETWORK_ACTIVITY/SOURCE/PORT",
},
isAllStringValues = False,
keywordField = None,
postOpMapper = None
),
}
class LimaCharlieBackend(BaseBackend):
"""Converts Sigma rule into LimaCharlie D&R rules. Contributed by LimaCharlie. https://limacharlie.io"""
identifier = "limacharlie"
active = True
config_required = False
default_config = ["limacharlie"]
def generate(self, sigmaparser):
# Take the log source information and figure out which set of mappings to use.
ruleConfig = sigmaparser.parsedyaml
ls_rule = ruleConfig['logsource']
try:
category = ls_rule['category']
except KeyError:
category = ""
try:
product = ls_rule['product']
except KeyError:
product = ""
# try:
# service = ls_rule['service']
# except KeyError:
# service = ""
# Don't use service for now, most Windows Event Logs
# uses a different service with no category, since we
# treat all Windows Event Logs together we can ignore
# the service.
service = ""
# See if we have a definition for the source combination.
mappingKey = "%s/%s/%s" % (product, category, service)
topFilter, preCond, mappings, isAllStringValues, keywordField, postOpMapper = _allFieldMappings.get(mappingKey, tuple([None, None, None, None, None, None]))
if mappings is None:
raise NotImplementedError("Log source %s/%s/%s not supported by backend." % (product, category, service))
# Field name conversions.
self._fieldMappingInEffect = mappings
# LC event type pre-selector for the type of data.
self._preCondition = preCond
# Are all the values treated as strings?
self._isAllStringValues = isAllStringValues
# Are we supporting keywords full text search?
self._keywordField = keywordField
# Call to fixup all operations after the fact.
self._postOpMapper = postOpMapper
# Call the original generation code.
detectComponent = super().generate(sigmaparser)
# We expect a string (yaml) as output, so if
# we get anything else we assume it's a core
# library value and just return it as-is.
if not isinstance( detectComponent, str):
return detectComponent
# This redundant to deserialize it right after
# generating the yaml, but we try to use the parent
# official class code as much as possible for future
# compatibility.
detectComponent = yaml.safe_load(detectComponent)
# Check that we got a proper node and not just a string
# which we don't really know what to do with.
if not isinstance(detectComponent, dict):
raise NotImplementedError("Selection combination not supported.")
# Apply top level filter.
detectComponent.update(topFilter)
# Now prepare the Response component.
respondComponents = [{
"action": "report",
"name": ruleConfig["title"],
}]
# Add a lot of the metadata available to the report.
if ruleConfig.get("tags", None) is not None:
respondComponents[0].setdefault("metadata", {})["tags"] = ruleConfig["tags"]
if ruleConfig.get("description", None) is not None:
respondComponents[0].setdefault("metadata", {})["description"] = ruleConfig["description"]
if ruleConfig.get("references", None) is not None:
respondComponents[0].setdefault("metadata", {})["references"] = ruleConfig["references"]
if ruleConfig.get("level", None) is not None:
respondComponents[0].setdefault("metadata", {})["level"] = ruleConfig["level"]
if ruleConfig.get("author", None) is not None:
respondComponents[0].setdefault("metadata", {})["author"] = ruleConfig["author"]
# Assemble it all as a single, complete D&R rule.
return yaml.safe_dump({
"detect": detectComponent,
"respond": respondComponents,
})
def generateQuery(self, parsed):
# We override the generateQuery function because
# we generate proper JSON structures internally
# and only convert to string (yaml) once the
# whole thing is assembled.
result = self.generateNode(parsed.parsedSearch)
if self._preCondition is not None:
result = {
"op": "and",
"rules": [
self._preCondition,
result,
]
}
if self._postOpMapper is not None:
result = self._postOpMapper(result)
return yaml.safe_dump(result)
def generateANDNode(self, node):
generated = [ self.generateNode(val) for val in node ]
filtered = [ g for g in generated if g is not None ]
if not filtered:
return None
# Map any possible keywords.
filtered = self._mapKeywordVals(filtered)
if 1 == len(filtered):
if self._postOpMapper is not None:
filtered[0] = self._postOpMapper(filtered[0])
return filtered[0]
result = {
"op": "and",
"rules": filtered,
}
if self._postOpMapper is not None:
result = self._postOpMapper(result)
return result
def generateORNode(self, node):
generated = [self.generateNode(val) for val in node]
filtered = [g for g in generated if g is not None]
if not filtered:
return None
# Map any possible keywords.
filtered = self._mapKeywordVals(filtered)
if 1 == len(filtered):
if self._postOpMapper is not None:
filtered[0] = self._postOpMapper(filtered[0])
return filtered[0]
result = {
"op": "or",
"rules": filtered,
}
if self._postOpMapper is not None:
result = self._postOpMapper(result)
return result
def generateNOTNode(self, node):
generated = self.generateNode(node.item)
if generated is None:
return None
if not isinstance(generated, dict):
raise NotImplementedError("Not operator not available on non-dict nodes.")
generated["not"] = not generated.get("not", False)
return generated
def generateSubexpressionNode(self, node):
return self.generateNode(node.items)
def generateListNode(self, node):
return [self.generateNode(value) for value in node]
def generateMapItemNode(self, node):
fieldname, value = node
fieldNameAndValCallback = None
# The mapping can be a dictionary of mapping or a callable
# to get the correct value.
if callable(self._fieldMappingInEffect):
fieldname = self._fieldMappingInEffect(fieldname)
else:
try:
# The mapping can also be a callable that will
# return a mapped key AND value.
if callable(self._fieldMappingInEffect[fieldname]):
fieldNameAndValCallback = self._fieldMappingInEffect[fieldname]
else:
fieldname = self._fieldMappingInEffect[fieldname]
except:
raise NotImplementedError("Field name %s not supported by backend." % (fieldname,))
# If fieldname returned is None, it's a special case where we
# ignore the node.
if fieldname is None:
return None
if isinstance(value, (int, str)):
if fieldNameAndValCallback is not None:
fieldname, value = fieldNameAndValCallback(fieldname, value)
op, newVal = self._valuePatternToLcOp(value)
newOp = {
"op": op,
"path": fieldname,
"case sensitive": False,
}
if op == "matches":
newOp["re"] = newVal
else:
newOp["value"] = newVal
if self._postOpMapper is not None:
newOp = self._postOpMapper(newOp)
return newOp
elif isinstance(value, list):
subOps = []
for v in value:
if fieldNameAndValCallback is not None:
fieldname, v = fieldNameAndValCallback(fieldname, v)
op, newVal = self._valuePatternToLcOp(v)
newOp = {
"op": op,
"path": fieldname,
"case sensitive": False,
}
if op == "matches":
newOp["re"] = newVal
else:
newOp["value"] = newVal
if self._postOpMapper is not None:
newOp = self._postOpMapper(newOp)
subOps.append(newOp)
if 1 == len(subOps):
return subOps[0]
return {
"op": "or",
"rules": subOps
}
elif isinstance(value, SigmaTypeModifier):
if isinstance(value, SigmaRegularExpressionModifier):
if fieldNameAndValCallback is not None:
fieldname, value = fieldNameAndValCallback(fieldname, value)
result = {
"op": "matches",
"path": fieldname,
"re": re.compile(value),
}
if self._postOpMapper is not None:
result = self._postOpMapper(result)
return result
else:
raise TypeError("Backend does not support TypeModifier: %s" % (str(type(value))))
elif value is None:
if fieldNameAndValCallback is not None:
fieldname, value = fieldNameAndValCallback(fieldname, value)
result = {
"op": "exists",
"not": True,
"path": fieldname,
}
if self._postOpMapper is not None:
result = self._postOpMapper(result)
return result
else:
raise TypeError("Backend does not support map values of type " + str(type(value)))
def generateValueNode(self, node):
return node
def _valuePatternToLcOp(self, val):
# Here we convert the string values supported by Sigma that
# can include wildcards into either proper values (string or int)
# or into altered values to be functionally equivalent using
# a few different LC D&R rule operators.
# No point evaluating non-strings.
if not isinstance(val, str):
return ("is", str(val) if self._isAllStringValues else val)
# Is there any wildcard in this string? If not, we can short circuit.
if "*" not in val and "?" not in val:
return ("is", val)
# Now we do a small optimization for the shortcut operators
# available in LC. We try to see if the wildcards are around
# the main value, but NOT within. If that's the case we can
# use the "starts with", "ends with" or "contains" operators.
isStartsWithWildcard = False
isEndsWithWildcard = False
tmpVal = val
if tmpVal.startswith("*"):
isStartsWithWildcard = True
tmpVal = tmpVal[1:]
if tmpVal.endswith("*") and not (tmpVal.endswith("\\*") and not tmpVal.endswith("\\\\*")):
isEndsWithWildcard = True
if tmpVal.endswith("\\\\*"):
# An extra \ had to be there so it didn't escapte the
# *, but since we plan on removing the *, we can also
# remove one \.
tmpVal = tmpVal[:-2]
else:
tmpVal = tmpVal[:-1]
# Check to see if there are any other wildcards. If there are
# we cannot use our shortcuts.
if "*" not in tmpVal and "?" not in tmpVal:
if isStartsWithWildcard and isEndsWithWildcard:
return ("contains", tmpVal)
if isStartsWithWildcard:
return ("ends with", tmpVal)
if isEndsWithWildcard:
return ("starts with", tmpVal)
# This is messy, but it is accurate in generating a RE based on
# the simplified wildcard system, while also supporting the
# escaping of those wildcards.
segments = []
tmpVal = val
while True:
nEscapes = 0
for i in range(len(tmpVal)):
# We keep a running count of backslash escape
# characters we see so that if we meet a wildcard
# we can tell whether the wildcard is escaped
# (with odd number of escapes) or if it's just a
# backslash literal before a wildcard (even number).
if "\\" == tmpVal[i]:
nEscapes += 1
continue
if "*" == tmpVal[i]:
if 0 == nEscapes:
segments.append(re.escape(tmpVal[:i]))
segments.append(".*")
elif nEscapes % 2 == 0:
segments.append(re.escape(tmpVal[:i - nEscapes]))
segments.append(tmpVal[i - nEscapes:i])
segments.append(".*")
else:
segments.append(re.escape(tmpVal[:i - nEscapes]))
segments.append(tmpVal[i - nEscapes:i + 1])
tmpVal = tmpVal[i + 1:]
break
if "?" == tmpVal[i]:
if 0 == nEscapes:
segments.append(re.escape(tmpVal[:i]))
segments.append(".")
elif nEscapes % 2 == 0:
segments.append(re.escape(tmpVal[:i - nEscapes]))
segments.append(tmpVal[i - nEscapes:i])
segments.append(".")
else:
segments.append(re.escape(tmpVal[:i - nEscapes]))
segments.append(tmpVal[i - nEscapes:i + 1])
tmpVal = tmpVal[i + 1:]
break
nEscapes = 0
else:
segments.append(re.escape(tmpVal))
break
val = ''.join(segments)
return ("matches", val)
def _mapKeywordVals(self, values):
# This function ensures that the list of values passed
# are proper D&R operations, if they are strings it indicates
# they were requested as keyword matches. We only support
# keyword matches when specified in the config. We generally just
# map them to the most common field in LC that makes sense.
mapped = []
for val in values:
# Non-keywords are just passed through.
if not isinstance(val, str):
mapped.append(val)
continue
if self._keywordField is None:
raise NotImplementedError("Full-text keyboard searches not supported.")
# This seems to be indicative only of "keywords" which are mostly
# representative of full-text searches. We don't suport that but
# in some data sources we can alias them to an actual field.
op, newVal = self._valuePatternToLcOp(val)
newOp = {
"op": op,
"path": self._keywordField,
}
if op == "matches":
newOp["re"] = newVal
else:
newOp["value"] = newVal
mapped.append(newOp)
return mapped
+2
View File
@@ -22,6 +22,8 @@ class LogPointBackend(SingleTextQueryBackend):
"""Converts Sigma rule into LogPoint query"""
identifier = "logpoint"
active = True
config_required = False
default_config = ["sysmon", "logpoint-windows"]
# \ -> \\
# \* -> \*
+2
View File
@@ -24,6 +24,8 @@ from .mixins import MultiRuleOutputMixin
class NetWitnessBackend(SingleTextQueryBackend):
"""Converts Sigma rule into NetWitness saved search. Contributed by @tuckner"""
identifier = "netwitness"
config_required = False
default_config = ["sysmon", "netwitness"]
active = True
reEscape = re.compile('(")')
reClear = None
+2
View File
@@ -23,6 +23,8 @@ class PowerShellBackend(SingleTextQueryBackend):
"""Converts Sigma rule into PowerShell event log cmdlets."""
identifier = "powershell"
active = True
config_required = False
default_config = ["sysmon", "powershell"]
options = (
("csv", False, "Return the results in CSV format instead of Powershell objects", None),
)
+2
View File
@@ -27,6 +27,8 @@ class QRadarBackend(SingleTextQueryBackend):
"""Converts Sigma rule into Qradar saved search. Contributed by SOC Prime. https://socprime.com"""
identifier = "qradar"
active = True
config_required = False
default_config = ["sysmon", "qradar"]
reEscape = re.compile('(")')
reClear = None
andToken = " and "
+2
View File
@@ -22,6 +22,8 @@ class QualysBackend(SingleTextQueryBackend):
"""Converts Sigma rule into Qualys saved search. Contributed by SOC Prime. https://socprime.com"""
identifier = "qualys"
active = True
config_required = False
default_config = ["sysmon", "qualys"]
andToken = " and "
orToken = " or "
notToken = "not "
+2
View File
@@ -32,6 +32,8 @@ class SumoLogicBackend(SingleTextQueryBackend):
"""Converts Sigma rule into SumoLogic query"""
identifier = "sumologic"
active = True
config_required = False
default_config = ["sysmon", "sumologic"]
index_field = "_index"
reClear = None
+3 -3
View File
@@ -202,11 +202,11 @@ class ConditionAND(ConditionBase):
"""AND Condition"""
op = COND_AND
def __init__(self, sigma=None, op=None, val1=None, val2=None):
if sigma == None and op == None and val1 == None and val2 == None: # no parameters given - initialize empty
def __init__(self, sigma=None, op=None, *args):
if sigma == None and op == None and len(args) == 0: # no parameters given - initialize empty
self.items = list()
else: # called by parser, use given values
self.items = [ val1, val2 ]
self.items = args
class ConditionOR(ConditionAND):
"""OR Condition"""
+20
View File
@@ -31,6 +31,26 @@ class SigmaContainsModifier(ListOrStringModifierMixin, SigmaTransformModifier):
val += "*"
return val
class SigmaStartswithModifier(ListOrStringModifierMixin, SigmaTransformModifier):
"""Add *-wildcard before and after all string(s)"""
identifier = "startswith"
active = True
def apply_str(self, val : str):
if not val.endswith("*"):
val += "*"
return val
class SigmaEndswithModifier(ListOrStringModifierMixin, SigmaTransformModifier):
"""Add *-wildcard before and after all string(s)"""
identifier = "endswith"
active = True
def apply_str(self, val : str):
if not val.startswith("*"):
val = "*" + val
return val
class SigmaAllValuesModifier(SigmaTransformModifier):
"""Override default OR-linking behavior for list with AND-linking of all list values"""
identifier = "all"
+11 -6
View File
@@ -168,6 +168,16 @@ if cmdargs.filter:
sys.exit(ERR_RULE_FILTER_PARSING)
sigmaconfigs = SigmaConfigurationChain()
backend_class = backends.getBackend(cmdargs.target)
if cmdargs.config is None:
if backend_class.config_required and not cmdargs.shoot_yourself_in_the_foot:
print("The backend you want to use usually requires a configuration to generate valid results. Please provide one with --config/-c.", file=sys.stderr)
print("Available choices for this backend (get complete list with --lists/-l):")
list_configurations(cmdargs.target)
sys.exit(ERR_CONFIG_REQUIRED)
if backend_class.default_config is not None:
cmdargs.config = backend_class.default_config
if cmdargs.config:
order = 0
for conf_name in cmdargs.config:
@@ -198,12 +208,7 @@ if cmdargs.config:
exit(ERR_CONFIG_PARSING)
backend_options = BackendOptions(cmdargs.backend_option, cmdargs.backend_config)
backend = backends.getBackend(cmdargs.target)(sigmaconfigs, backend_options)
if backend.config_required and cmdargs.config is None and not cmdargs.shoot_yourself_in_the_foot:
print("The backend you want to use usually requires a configuration to generate valid results. Please provide one with --config/-c.", file=sys.stderr)
print("Available choices for this backend (get complete list with --lists/-l):")
list_configurations(cmdargs.target)
sys.exit(ERR_CONFIG_REQUIRED)
backend = backend_class(sigmaconfigs, backend_options)
filename = cmdargs.output
if filename: