From 72c0672219afe9e390248a1c8679a87a226e75b2 Mon Sep 17 00:00:00 2001 From: Victor Fernandez III <48382964+cyberphor@users.noreply.github.com> Date: Sat, 5 Aug 2023 23:14:04 -0400 Subject: [PATCH] Updated backend to pySigma v0.10.1 --- .gitignore | 3 +- README.md | 8 +- poetry.lock | 266 +++++++---------------- pyproject.toml | 9 +- rules/net_connection_win_wscript.yml | 10 + sigma/backends/powershell/powershell.py | 179 +++++++-------- sigma/pipelines/powershell/__init__.py | 6 +- sigma/pipelines/powershell/powershell.py | 21 +- sigma2powershell.py | 25 ++- 9 files changed, 203 insertions(+), 324 deletions(-) create mode 100644 rules/net_connection_win_wscript.yml diff --git a/.gitignore b/.gitignore index 20651f1..179df0a 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ .vscode/ cov.xml dist/ -docs/_build \ No newline at end of file +docs/_build +backup/ \ No newline at end of file diff --git a/README.md b/README.md index c3ebdc1..3565790 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,13 @@ It currently supports the following output formats: ## Testing ```python python -m pip install --user pytest -python -m pytest +python -m pytest # test all functions +python -m pytest tests/test_backend_powershell.py::test_powershell_and_expression # test a specific function +``` + +## Updating to the Latest Version of pySigma +```python +python -m poetry add pysigma@latest ``` ## References diff --git a/poetry.lock b/poetry.lock index 009622e..15ce4c8 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,19 +1,3 @@ -[[package]] -name = "attrs" -version = "22.2.0" -description = "Classes Without Boilerplate" -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.extras] -cov = ["attrs", "coverage-enable-subprocess", "coverage[toml] (>=5.3)"] -dev = ["attrs"] -docs = ["furo", "sphinx", "myst-parser", "zope.interface", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier"] -tests = ["attrs", "zope.interface"] -tests-no-zope = ["hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist", "cloudpickle", "mypy (>=0.971,<0.990)", "pytest-mypy-plugins"] -tests_no_zope = ["hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist", "cloudpickle", "mypy (>=0.971,<0.990)", "pytest-mypy-plugins"] - [[package]] name = "certifi" version = "2022.12.7" @@ -31,52 +15,33 @@ optional = false python-versions = "*" [[package]] -name = "colorama" -version = "0.4.6" -description = "Cross-platform colored terminal text." -category = "dev" +name = "idna" +version = "3.4" +description = "Internationalized Domain Names in Applications (IDNA)" +category = "main" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +python-versions = ">=3.5" [[package]] -name = "coverage" -version = "7.1.0" -description = "Code coverage measurement for Python" -category = "dev" +name = "jinja2" +version = "3.1.2" +description = "A very fast and expressive template engine." +category = "main" optional = false python-versions = ">=3.7" [package.dependencies] -tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} - -[package.extras] -toml = ["tomli"] - -[[package]] -name = "exceptiongroup" -version = "1.1.0" -description = "Backport of PEP 654 (exception groups)" -category = "dev" -optional = false -python-versions = ">=3.7" +MarkupSafe = ">=2.0" [package.extras] -test = ["pytest (>=6)"] +i18n = ["Babel (>=2.7)"] [[package]] -name = "idna" -version = "3.4" -description = "Internationalized Domain Names in Applications (IDNA)" +name = "markupsafe" +version = "2.1.3" +description = "Safely add untrusted strings to HTML/XML markup." category = "main" optional = false -python-versions = ">=3.5" - -[[package]] -name = "iniconfig" -version = "2.0.0" -description = "brain-dead simple config-ini parsing" -category = "dev" -optional = false python-versions = ">=3.7" [[package]] @@ -87,18 +52,6 @@ category = "main" optional = false python-versions = ">=3.7" -[[package]] -name = "pluggy" -version = "1.0.0" -description = "plugin and hook calling mechanisms for python" -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.extras] -testing = ["pytest-benchmark", "pytest"] -dev = ["tox", "pre-commit"] - [[package]] name = "pyparsing" version = "3.0.9" @@ -112,53 +65,19 @@ diagrams = ["railroad-diagrams", "jinja2"] [[package]] name = "pysigma" -version = "0.9.1" +version = "0.10.1" description = "Sigma rule processing and conversion tools" category = "main" optional = false python-versions = ">=3.8,<4.0" [package.dependencies] +jinja2 = ">=3.1.2,<4.0.0" packaging = ">=22.0,<23.0" pyparsing = ">=3.0.7,<4.0.0" pyyaml = ">=6.0,<7.0" requests = ">=2.28.1,<3.0.0" -[[package]] -name = "pytest" -version = "7.2.1" -description = "pytest: simple powerful testing with Python" -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -attrs = ">=19.2.0" -colorama = {version = "*", markers = "sys_platform == \"win32\""} -exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} -iniconfig = "*" -packaging = "*" -pluggy = ">=0.12,<2.0" -tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} - -[package.extras] -testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] - -[[package]] -name = "pytest-cov" -version = "4.0.0" -description = "Pytest plugin for measuring coverage." -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -coverage = {version = ">=5.2.1", extras = ["toml"]} -pytest = ">=4.6" - -[package.extras] -testing = ["fields", "hunter", "process-tests", "six", "pytest-xdist", "virtualenv"] - [[package]] name = "pyyaml" version = "6.0" @@ -185,14 +104,6 @@ urllib3 = ">=1.21.1,<1.27" socks = ["PySocks (>=1.5.6,!=1.5.7)"] use_chardet_on_py3 = ["chardet (>=3.0.2,<6)"] -[[package]] -name = "tomli" -version = "2.0.1" -description = "A lil' TOML parser" -category = "dev" -optional = false -python-versions = ">=3.7" - [[package]] name = "urllib3" version = "1.26.14" @@ -209,13 +120,9 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [metadata] lock-version = "1.1" python-versions = "^3.8" -content-hash = "e5ce932a155f04c363432227b703f387705e4daa2af8a4fb931a4106d6bfb62b" +content-hash = "b338cf38f46041f1fad20155967f9d408a55e7bd5d8bbcfe8d416b4887c0b4d3" [metadata.files] -attrs = [ - {file = "attrs-22.2.0-py3-none-any.whl", hash = "sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836"}, - {file = "attrs-22.2.0.tar.gz", hash = "sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99"}, -] certifi = [ {file = "certifi-2022.12.7-py3-none-any.whl", hash = "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18"}, {file = "certifi-2022.12.7.tar.gz", hash = "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3"}, @@ -310,98 +217,77 @@ charset-normalizer = [ {file = "charset_normalizer-3.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:0a11e971ed097d24c534c037d298ad32c6ce81a45736d31e0ff0ad37ab437d59"}, {file = "charset_normalizer-3.0.1-py3-none-any.whl", hash = "sha256:7e189e2e1d3ed2f4aebabd2d5b0f931e883676e51c7624826e0a4e5fe8a0bf24"}, ] -colorama = [ - {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, - {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, -] -coverage = [ - {file = "coverage-7.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3b946bbcd5a8231383450b195cfb58cb01cbe7f8949f5758566b881df4b33baf"}, - {file = "coverage-7.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ec8e767f13be637d056f7e07e61d089e555f719b387a7070154ad80a0ff31801"}, - {file = "coverage-7.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4a5a5879a939cb84959d86869132b00176197ca561c664fc21478c1eee60d75"}, - {file = "coverage-7.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b643cb30821e7570c0aaf54feaf0bfb630b79059f85741843e9dc23f33aaca2c"}, - {file = "coverage-7.1.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32df215215f3af2c1617a55dbdfb403b772d463d54d219985ac7cd3bf124cada"}, - {file = "coverage-7.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:33d1ae9d4079e05ac4cc1ef9e20c648f5afabf1a92adfaf2ccf509c50b85717f"}, - {file = "coverage-7.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:29571503c37f2ef2138a306d23e7270687c0efb9cab4bd8038d609b5c2393a3a"}, - {file = "coverage-7.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:63ffd21aa133ff48c4dff7adcc46b7ec8b565491bfc371212122dd999812ea1c"}, - {file = "coverage-7.1.0-cp310-cp310-win32.whl", hash = "sha256:4b14d5e09c656de5038a3f9bfe5228f53439282abcab87317c9f7f1acb280352"}, - {file = "coverage-7.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:8361be1c2c073919500b6601220a6f2f98ea0b6d2fec5014c1d9cfa23dd07038"}, - {file = "coverage-7.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:da9b41d4539eefd408c46725fb76ecba3a50a3367cafb7dea5f250d0653c1040"}, - {file = "coverage-7.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c5b15ed7644ae4bee0ecf74fee95808dcc34ba6ace87e8dfbf5cb0dc20eab45a"}, - {file = "coverage-7.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d12d076582507ea460ea2a89a8c85cb558f83406c8a41dd641d7be9a32e1274f"}, - {file = "coverage-7.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2617759031dae1bf183c16cef8fcfb3de7617f394c813fa5e8e46e9b82d4222"}, - {file = "coverage-7.1.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4e4881fa9e9667afcc742f0c244d9364d197490fbc91d12ac3b5de0bf2df146"}, - {file = "coverage-7.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9d58885215094ab4a86a6aef044e42994a2bd76a446dc59b352622655ba6621b"}, - {file = "coverage-7.1.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:ffeeb38ee4a80a30a6877c5c4c359e5498eec095878f1581453202bfacc8fbc2"}, - {file = "coverage-7.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3baf5f126f30781b5e93dbefcc8271cb2491647f8283f20ac54d12161dff080e"}, - {file = "coverage-7.1.0-cp311-cp311-win32.whl", hash = "sha256:ded59300d6330be27bc6cf0b74b89ada58069ced87c48eaf9344e5e84b0072f7"}, - {file = "coverage-7.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:6a43c7823cd7427b4ed763aa7fb63901ca8288591323b58c9cd6ec31ad910f3c"}, - {file = "coverage-7.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7a726d742816cb3a8973c8c9a97539c734b3a309345236cd533c4883dda05b8d"}, - {file = "coverage-7.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc7c85a150501286f8b56bd8ed3aa4093f4b88fb68c0843d21ff9656f0009d6a"}, - {file = "coverage-7.1.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f5b4198d85a3755d27e64c52f8c95d6333119e49fd001ae5798dac872c95e0f8"}, - {file = "coverage-7.1.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ddb726cb861c3117a553f940372a495fe1078249ff5f8a5478c0576c7be12050"}, - {file = "coverage-7.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:51b236e764840a6df0661b67e50697aaa0e7d4124ca95e5058fa3d7cbc240b7c"}, - {file = "coverage-7.1.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:7ee5c9bb51695f80878faaa5598040dd6c9e172ddcf490382e8aedb8ec3fec8d"}, - {file = "coverage-7.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c31b75ae466c053a98bf26843563b3b3517b8f37da4d47b1c582fdc703112bc3"}, - {file = "coverage-7.1.0-cp37-cp37m-win32.whl", hash = "sha256:3b155caf3760408d1cb903b21e6a97ad4e2bdad43cbc265e3ce0afb8e0057e73"}, - {file = "coverage-7.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:2a60d6513781e87047c3e630b33b4d1e89f39836dac6e069ffee28c4786715f5"}, - {file = "coverage-7.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f2cba5c6db29ce991029b5e4ac51eb36774458f0a3b8d3137241b32d1bb91f06"}, - {file = "coverage-7.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:beeb129cacea34490ffd4d6153af70509aa3cda20fdda2ea1a2be870dfec8d52"}, - {file = "coverage-7.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0c45948f613d5d18c9ec5eaa203ce06a653334cf1bd47c783a12d0dd4fd9c851"}, - {file = "coverage-7.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef382417db92ba23dfb5864a3fc9be27ea4894e86620d342a116b243ade5d35d"}, - {file = "coverage-7.1.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c7c0d0827e853315c9bbd43c1162c006dd808dbbe297db7ae66cd17b07830f0"}, - {file = "coverage-7.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e5cdbb5cafcedea04924568d990e20ce7f1945a1dd54b560f879ee2d57226912"}, - {file = "coverage-7.1.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9817733f0d3ea91bea80de0f79ef971ae94f81ca52f9b66500c6a2fea8e4b4f8"}, - {file = "coverage-7.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:218fe982371ac7387304153ecd51205f14e9d731b34fb0568181abaf7b443ba0"}, - {file = "coverage-7.1.0-cp38-cp38-win32.whl", hash = "sha256:04481245ef966fbd24ae9b9e537ce899ae584d521dfbe78f89cad003c38ca2ab"}, - {file = "coverage-7.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:8ae125d1134bf236acba8b83e74c603d1b30e207266121e76484562bc816344c"}, - {file = "coverage-7.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2bf1d5f2084c3932b56b962a683074a3692bce7cabd3aa023c987a2a8e7612f6"}, - {file = "coverage-7.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:98b85dd86514d889a2e3dd22ab3c18c9d0019e696478391d86708b805f4ea0fa"}, - {file = "coverage-7.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38da2db80cc505a611938d8624801158e409928b136c8916cd2e203970dde4dc"}, - {file = "coverage-7.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3164d31078fa9efe406e198aecd2a02d32a62fecbdef74f76dad6a46c7e48311"}, - {file = "coverage-7.1.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db61a79c07331e88b9a9974815c075fbd812bc9dbc4dc44b366b5368a2936063"}, - {file = "coverage-7.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9ccb092c9ede70b2517a57382a601619d20981f56f440eae7e4d7eaafd1d1d09"}, - {file = "coverage-7.1.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:33ff26d0f6cc3ca8de13d14fde1ff8efe1456b53e3f0273e63cc8b3c84a063d8"}, - {file = "coverage-7.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d47dd659a4ee952e90dc56c97d78132573dc5c7b09d61b416a9deef4ebe01a0c"}, - {file = "coverage-7.1.0-cp39-cp39-win32.whl", hash = "sha256:d248cd4a92065a4d4543b8331660121b31c4148dd00a691bfb7a5cdc7483cfa4"}, - {file = "coverage-7.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:7ed681b0f8e8bcbbffa58ba26fcf5dbc8f79e7997595bf071ed5430d8c08d6f3"}, - {file = "coverage-7.1.0-pp37.pp38.pp39-none-any.whl", hash = "sha256:755e89e32376c850f826c425ece2c35a4fc266c081490eb0a841e7c1cb0d3bda"}, - {file = "coverage-7.1.0.tar.gz", hash = "sha256:10188fe543560ec4874f974b5305cd1a8bdcfa885ee00ea3a03733464c4ca265"}, -] -exceptiongroup = [ - {file = "exceptiongroup-1.1.0-py3-none-any.whl", hash = "sha256:327cbda3da756e2de031a3107b81ab7b3770a602c4d16ca618298c526f4bec1e"}, - {file = "exceptiongroup-1.1.0.tar.gz", hash = "sha256:bcb67d800a4497e1b404c2dd44fca47d3b7a5e5433dbab67f96c1a685cdfdf23"}, -] idna = [ {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, ] -iniconfig = [ - {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, - {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +jinja2 = [ + {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, + {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, +] +markupsafe = [ + {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-win32.whl", hash = "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-win32.whl", hash = "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-win_amd64.whl", hash = "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-win32.whl", hash = "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-win_amd64.whl", hash = "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-win32.whl", hash = "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba"}, + {file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"}, ] packaging = [ {file = "packaging-22.0-py3-none-any.whl", hash = "sha256:957e2148ba0e1a3b282772e791ef1d8083648bc131c8ab0c1feba110ce1146c3"}, {file = "packaging-22.0.tar.gz", hash = "sha256:2198ec20bd4c017b8f9717e00f0c8714076fc2fd93816750ab48e2c41de2cfd3"}, ] -pluggy = [ - {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, - {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, -] pyparsing = [ {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"}, ] pysigma = [ - {file = "pysigma-0.9.1-py3-none-any.whl", hash = "sha256:15830da6ef12cc27597d4df8e4e53f1979420caa48fdb41d3baf5f16807c8d9e"}, - {file = "pysigma-0.9.1.tar.gz", hash = "sha256:bbe429d3bbeaaa6b9ef82471844ac46eb020a7264545d9d5fb448581b4699b09"}, -] -pytest = [ - {file = "pytest-7.2.1-py3-none-any.whl", hash = "sha256:c7c6ca206e93355074ae32f7403e8ea12163b1163c976fee7d4d84027c162be5"}, - {file = "pytest-7.2.1.tar.gz", hash = "sha256:d45e0952f3727241918b8fd0f376f5ff6b301cc0777c6f9a556935c92d8a7d42"}, -] -pytest-cov = [ - {file = "pytest-cov-4.0.0.tar.gz", hash = "sha256:996b79efde6433cdbd0088872dbc5fb3ed7fe1578b68cdbba634f14bb8dd0470"}, - {file = "pytest_cov-4.0.0-py3-none-any.whl", hash = "sha256:2feb1b751d66a8bd934e5edfa2e961d11309dc37b73b0eabe73b5945fee20f6b"}, + {file = "pysigma-0.10.1-py3-none-any.whl", hash = "sha256:15674a372ffad44b0227037be9fd7bd6ecf530323c6de8ce1e316c9fdaa8853a"}, + {file = "pysigma-0.10.1.tar.gz", hash = "sha256:1b00758a4abc3ba74436a3937bfb07607e92c46e53d01e600d8d5c78aa510682"}, ] pyyaml = [ {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, @@ -442,10 +328,6 @@ requests = [ {file = "requests-2.28.2-py3-none-any.whl", hash = "sha256:64299f4909223da747622c030b781c0d7811e359c37124b4bd368fb8c6518baa"}, {file = "requests-2.28.2.tar.gz", hash = "sha256:98b1b2782e3c6c4904938b84c0eb932721069dfdb9134313beff7c83c2df24bf"}, ] -tomli = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, -] urllib3 = [ {file = "urllib3-1.26.14-py2.py3-none-any.whl", hash = "sha256:75edcdc2f7d85b137124a6c3c9fc3933cdeaa12ecb9a6a959f22797a0feca7e1"}, {file = "urllib3-1.26.14.tar.gz", hash = "sha256:076907bf8fd355cde77728471316625a4d2f7e713c125f51953bb5b3eecf4f72"}, diff --git a/pyproject.toml b/pyproject.toml index 8b34e51..b0f6abd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "pySigma-backend-powershell" -version = "0.1.0" +version = "0.1.1" description = "pySigma PowerShell Backend" authors = ["Victor Fernandez III <@cyberphor>"] license = "MIT" @@ -11,12 +11,7 @@ packages = [ [tool.poetry.dependencies] python = "^3.8" -pysigma = "^0.9.1" - -[tool.poetry.dev-dependencies] -pytest = "^7.2.1" -pytest-cov = "^4.0.0" -coverage = "^7.1.0" +pysigma = "^0.10.1" [build-system] requires = ["poetry-core>=1.0.0"] diff --git a/rules/net_connection_win_wscript.yml b/rules/net_connection_win_wscript.yml new file mode 100644 index 0000000..e75889d --- /dev/null +++ b/rules/net_connection_win_wscript.yml @@ -0,0 +1,10 @@ +logsource: + category: network_connection + product: windows +detection: + selection: + Image|endswith: '\wscript.exe' + Initiated: 'true' + DestinationPort: + - 25 + condition: selection \ No newline at end of file diff --git a/sigma/backends/powershell/powershell.py b/sigma/backends/powershell/powershell.py index e4882e7..c95d503 100644 --- a/sigma/backends/powershell/powershell.py +++ b/sigma/backends/powershell/powershell.py @@ -1,23 +1,28 @@ -from sigma.conditions import ConditionItem, ConditionAND, ConditionOR, ConditionNOT, ConditionFieldEqualsValueExpression -from sigma.conversion.base import TextQueryBackend, SpecialChars -from sigma.conversion.deferred import DeferredQueryExpression +from collections import defaultdict +from sigma.conditions import ConditionItem, ConditionAND, ConditionOR, ConditionNOT +from sigma.conversion.base import TextQueryBackend from sigma.conversion.state import ConversionState +from sigma.pipelines.powershell import powershell_pipeline +from sigma.processing.pipeline import ProcessingPipeline from sigma.rule import SigmaRule -from sigma.types import SigmaCompareExpression -from typing import ClassVar, Dict, Tuple, Pattern, List, Union +from sigma.types import SigmaCompareExpression, SigmaRegularExpressionFlag +from typing import ClassVar, Dict, Tuple, Pattern, List, Any, Optional from re import compile class PowerShellBackend(TextQueryBackend): """PowerShell backend.""" name: ClassVar[str] = "PowerShell backend" formats: Dict[str, str] = { - "default": "plain PowerShell queries", - "script": "a PowerShell script", - "xml": "XML documents", - "xpath": "XML strings", - "subscription": "Windows event subscriptions" + "default": "PowerShell sentences", + "script": "PowerShell scripts", } requires_pipeline: bool = False + processing_pipeline: powershell_pipeline + last_processing_pipeline: powershell_pipeline + output_format_processing_pipeline: ClassVar[Dict[str, ProcessingPipeline]] = defaultdict( + ProcessingPipeline + ) + # Operator precedence: tuple of Condition{AND,OR,NOT} in order of precedence. # The backend generates grouping if required precedence: ClassVar[Tuple[ConditionItem, ConditionItem, ConditionItem]] = (ConditionNOT, ConditionAND, ConditionOR) @@ -36,40 +41,64 @@ class PowerShellBackend(TextQueryBackend): ### Quoting field_quote: ClassVar[str] = "" field_quote_pattern: ClassVar[Pattern] = compile("^\\w+$") - field_quote_pattern_negation : ClassVar[bool] = True # NEW + field_quote_pattern_negation: ClassVar[bool] = True ### Escaping - field_escape: ClassVar[str] = "\\" - field_escape_quote: ClassVar[bool] = False - field_escape_pattern: ClassVar[Pattern] = compile("\\s") + field_escape: ClassVar[str] = "\\" # Character to escape particular parts defined in field_escape_pattern. + field_escape_quote: ClassVar[bool] = False # Escape quote string defined in field_quote + field_escape_pattern: ClassVar[Pattern] = compile("\\s") # All matches of this pattern are prepended with the string contained in field_escape. ## Values - str_quote: ClassVar[str] = '"' - escape_char: ClassVar[str] = "\\" - wildcard_multi: ClassVar[str] = "*" - wildcard_single: ClassVar[str] = "*" - add_escaped: ClassVar[str] = "\\" - filter_chars: ClassVar[str] = "" - bool_values: ClassVar[Dict[bool, str]] = {True: "$true", False:"$false"} + str_quote: ClassVar[str] = '"' # string quoting character (added as escaping character) + escape_char: ClassVar[str] = "\\" # Escaping character for special characrers inside string + wildcard_multi: ClassVar[str] = "*" # Character used as multi-character wildcard + wildcard_single: ClassVar[str] = "*" # Character used as single-character wildcard + add_escaped: ClassVar[str] = "\\" # Characters quoted in addition to wildcards and string quote + filter_chars: ClassVar[str] = "" # Characters filtered + bool_values: ClassVar[Dict[bool, str]] = { # Values to which boolean values are mapped. + True: "$true", + False: "$false", + } # String matching operators. if None is appropriate, eq_token is used. - startswith_expression: ClassVar[str] = "{field} -like {value}" - endswith_expression: ClassVar[str] = "{field} -like {value}" - contains_expression: ClassVar[str] = "{field} -contains {value}" - wildcard_match_expression: ClassVar[str] = "{field} -like {value}" + startswith_expression: ClassVar[str] = "{field}.StartsWith({value})" + endswith_expression: ClassVar[str] = "{field}.EndsWith({value})" + contains_expression: ClassVar[str] = "{field}.Contains({value})" + wildcard_match_expression: ClassVar[str] = "{field} -like {value}" # Special expression if wildcards can't be matched with the eq_token operator # Regular expressions re_expression: ClassVar[str] = '{field} -match "{regex}"' - re_escape_char: ClassVar[str] = "\\" - re_escape: ClassVar[Tuple[str]] = () + re_escape_char: ClassVar[str] = "\\" # Character used for escaping in regular expressions + re_escape: ClassVar[Tuple[str]] = () # List of strings that are escaped + re_escape_escape_char: bool = True # If True, the escape character is also escaped + re_flag_prefix: bool = True # If True, the flags are prepended as (?x) group at the beginning of the regular expression, e.g. (?i). If this is not supported by the target, it should be set to False. + # Mapping from SigmaRegularExpressionFlag values to static string templates that are used in + # flag_x placeholders in re_expression template. + # By default, i, m and s are defined. If a flag is not supported by the target query language, + # remove it from re_flags or don't define it to ensure proper error handling in case of appearance. + re_flags: Dict[SigmaRegularExpressionFlag, str] = { + SigmaRegularExpressionFlag.IGNORECASE: "i", + SigmaRegularExpressionFlag.MULTILINE : "m", + SigmaRegularExpressionFlag.DOTALL : "s", + } + + # Case sensitive string matching expression. String is quoted/escaped like a normal string. + # Placeholders {field} and {value} are replaced with field name and quoted/escaped string. + case_sensitive_match_expression: ClassVar[str] = "{field} casematch {value}" + # Case sensitive string matching operators similar to standard string matching. If not provided, + # case_sensitive_match_expression is used. + case_sensitive_startswith_expression: ClassVar[str] = "{field} casematch_startswith {value}" + case_sensitive_endswith_expression: ClassVar[str] = "{field} casematch_endswith {value}" + case_sensitive_contains_expression: ClassVar[str] = "{field} casematch_contains {value}" # cidr expressions - cidr_wildcard: ClassVar[str] = "*" # Character used as single wildcard + cidr_wildcard: ClassVar[str] = "*" # Character used as single wildcard # cidr_expression: ClassVar[str] = "cidrmatch({field}, {value})" # CIDR expression query as format string with placeholders {field} = {value} # cidr_in_list_expression: ClassVar[str] = "{field} in ({value})" # CIDR expression query as format string with placeholders {field} = in({list}) # Numeric comparison operators - compare_op_expression: ClassVar[str] = "{field} {operator} {value}" + compare_op_expression: ClassVar[str] = "{field} {operator} {value}" # Compare operation query as format string with placeholders {field}, {operator} and {value} + # Mapping between CompareOperators elements and strings used as replacement for {operator} in compare_op_expression compare_operators: ClassVar[Dict[SigmaCompareExpression.CompareOperators, str]] = { SigmaCompareExpression.CompareOperators.LT: "-lt", SigmaCompareExpression.CompareOperators.LTE: "-le", @@ -77,84 +106,42 @@ class PowerShellBackend(TextQueryBackend): SigmaCompareExpression.CompareOperators.GTE: "-ge", } + # Expression for comparing two event fields + field_equals_field_expression: ClassVar[Optional[str]] = None # Field comparison expression with the placeholders {field1} and {field2} corresponding to left field and right value side of Sigma detection item + field_equals_field_escaping_quoting: Tuple[bool, bool] = (True, True) # If regular field-escaping/quoting is applied to field1 and field2. A custom escaping/quoting can be implemented in the convert_condition_field_eq_field_escape_and_quote method. + # Null/None expressions - field_null_expression : ClassVar[str] = "{field} is null" # Expression for field has null value as format string with {field} placeholder for field name + field_null_expression: ClassVar[str] = "{field} -is null" # Expression for field has null value as format string with {field} placeholder for field name + + # Field existence condition expressions. + field_exists_expression: ClassVar[str] = "exists({field})" # Expression for field existence as format string with {field} placeholder for field name + field_not_exists_expression: ClassVar[str] = "notexists({field})" # Expression for field non-existence as format string with {field} placeholder for field name. If not set, field_exists_expression is negated with boolean NOT. # Field value in list, e.g. "field in (value list)" or "field containsall (value list)" - convert_or_as_in: ClassVar[bool] = True # Convert OR as in-expression - convert_and_as_in: ClassVar[bool] = True # Convert AND as in-expression - in_expressions_allow_wildcards: ClassVar[bool] = False # Values in list can contain wildcards. If set to False (default) only plain values are converted into in-expressions. - field_in_list_expression : ClassVar[str] = "{field} {op} ({list})" # Expression for field in list of values as format string with placeholders {field}, {op} and {list} - or_in_operator: ClassVar[str] = "-in" # Operator used to convert OR into in-expressions. Must be set if convert_or_as_in is set - and_in_operator: ClassVar[str] = "contains-all" # Operator used to convert AND into in-expressions. Must be set if convert_and_as_in is set - list_separator: ClassVar[str] = ", " # List element separator + convert_or_as_in: ClassVar[bool] = True # Convert OR as in-expression + convert_and_as_in: ClassVar[bool] = True # Convert AND as in-expression + in_expressions_allow_wildcards: ClassVar[bool] = False # Values in list can contain wildcards. If set to False (default) only plain values are converted into in-expressions. + field_in_list_expression: ClassVar[str] = "{field} {op} ({list})" # Expression for field in list of values as format string with placeholders {field}, {op} and {list} + or_in_operator: ClassVar[str] = "in" # Operator used to convert OR into in-expressions. Must be set if convert_or_as_in is set + and_in_operator: ClassVar[str] = "contains-all" # Operator used to convert AND into in-expressions. Must be set if convert_and_as_in is set + list_separator: ClassVar[str] = ", " # List element separator # Value not bound to a field - unbound_value_str_expression : ClassVar[str] = '"{value}"' # Expression for string value not bound to a field as format string with placeholder {value} - unbound_value_num_expression : ClassVar[str] = '{value}' # Expression for number value not bound to a field as format string with placeholder {value} - unbound_value_re_expression : ClassVar[str] = '_=~{value}' # Expression for regular expression not bound to a field as format string with placeholder {value} + unbound_value_str_expression: ClassVar[str] = '"{value}"' # Expression for string value not bound to a field as format string with placeholder {value} + unbound_value_num_expression: ClassVar[str] = '{value}' # Expression for number value not bound to a field as format string with placeholder {value} + unbound_value_re_expression: ClassVar[str] = '_=~{value}' # Expression for regular expression not bound to a field as format string with placeholder {value} and {flag_x} as described for re_expression # Query finalization: appending and concatenating deferred query part - deferred_start: ClassVar[str] = "\n| " - deferred_separator: ClassVar[str] = "\n| " - deferred_only_query: ClassVar[str] = "*" - - def convert_condition_field_eq_val_str(self, cond: ConditionFieldEqualsValueExpression, state: ConversionState) -> Union[str, DeferredQueryExpression]: - """Conversion of field = string value expressions""" - try: - if ( - self.startswith_expression is not None - and cond.value.endswith(SpecialChars.WILDCARD_MULTI) - and not cond.value[:-1].contains_special() - ): - expr = self.startswith_expression - value = cond.value # this was originally "value = cond.value[:-1]" - elif ( - self.endswith_expression is not None - and cond.value.startswith(SpecialChars.WILDCARD_MULTI) - and not cond.value[1:].contains_special() - ): - expr = self.endswith_expression - value = cond.value[1:] - elif ( - self.contains_expression is not None - and cond.value.startswith(SpecialChars.WILDCARD_MULTI) - and cond.value.endswith(SpecialChars.WILDCARD_MULTI) - and not cond.value[1:-1].contains_special() - ): - expr = self.contains_expression - value = cond.value[1:-1] - elif ( - self.wildcard_match_expression is not None - and cond.value.contains_special() - ): - expr = self.wildcard_match_expression - value = cond.value - else: - expr = "{field}" + self.eq_token + "{value}" - value = cond.value - return expr.format(field=self.escape_and_quote_field(cond.field), value=self.convert_value_str(value, state)) - except TypeError: - raise NotImplementedError("Field equals string value expressions with strings are not supported by the backend.") - - def convert_condition_not(self, cond: ConditionNOT, state: ConversionState) -> Union[str, DeferredQueryExpression]: - """Conversion of NOT conditions.""" - arg = cond.args[0] - if arg.__class__ in self.precedence: - return self.not_token + self.token_separator + self.convert_condition_group(arg, state) - else: - expr = self.convert_condition(arg, state) - if isinstance(expr, DeferredQueryExpression): - return expr.negate() - else: - return f'{arg.field} -ne "{arg.value}"' + deferred_start: ClassVar[str] = "\n| " # String used as separator between main query and deferred parts + deferred_separator: ClassVar[str] = "\n| " # String used to join multiple deferred query parts + deferred_only_query: ClassVar[str] = "*" # String used as query if final query only contains deferred expression - def finalize_query_default(self, rule: SigmaRule, query: str, index: int, state: ConversionState) -> str: + def finalize_query_default(self, rule: SigmaRule, query: Any, index: int, state: ConversionState) -> Any: if hasattr(rule, "eventid"): filter = f'-FilterHashTable @{{LogName = "{rule.logsource.service}"; Id = {rule.eventid}}} | ' else: filter = f'-LogName "{rule.logsource.service}" | ' return "Get-WinEvent " + filter + f"Read-WinEvent | Where-Object {{{query}}}" - def finalize_output_default(self, queries: List[str]) -> str: - return list(queries) \ No newline at end of file + def finalize_output_default(self, queries: List[str]) -> Any: + return queries \ No newline at end of file diff --git a/sigma/pipelines/powershell/__init__.py b/sigma/pipelines/powershell/__init__.py index 9379f40..e974175 100644 --- a/sigma/pipelines/powershell/__init__.py +++ b/sigma/pipelines/powershell/__init__.py @@ -1,2 +1,6 @@ from .powershell import powershell_pipeline -# TODO: add all pipelines that should be exposed to the user of your backend in the import statement above. \ No newline at end of file +# TODO: add all pipelines that should be exposed to the user of your backend in the import statement above. + +pipelines = { + "powershell_pipeline": powershell_pipeline +} \ No newline at end of file diff --git a/sigma/pipelines/powershell/powershell.py b/sigma/pipelines/powershell/powershell.py index 8271033..25776d4 100644 --- a/sigma/pipelines/powershell/powershell.py +++ b/sigma/pipelines/powershell/powershell.py @@ -2,9 +2,8 @@ from sigma.pipelines.common import logsource_windows, windows_logsource_mapping from sigma.processing.conditions import IncludeFieldCondition, LogsourceCondition from sigma.processing.pipeline import ProcessingPipeline, ProcessingItem -from sigma.processing.transformations import AddFieldnamePrefixTransformation, ChangeLogsourceTransformation, DropDetectionItemTransformation, RuleFailureTransformation, Transformation +from sigma.processing.transformations import AddConditionTransformation, AddFieldnamePrefixTransformation, ChangeLogsourceTransformation, DetectionItemFailureTransformation, DropDetectionItemTransformation, FieldMappingTransformation, RuleFailureTransformation, SetStateTransformation, Transformation from sigma.rule import SigmaRule -from re import compile @dataclass class PromoteDetectionItemTransformation(Transformation): @@ -18,16 +17,6 @@ def apply(self, pipeline, rule: SigmaRule) -> None: # TODO: address situations where the detection item has more than one value setattr(rule, self.field.lower(), detection_item.value[0]) -@dataclass -class RemoveWhiteSpaceTransformation(Transformation): - """Remove white space characters from detection item field names.""" - def apply(self, pipeline, rule: SigmaRule) -> None: - super().apply(pipeline, rule) - for detection in rule.detection.detections.values(): - for detection_item in detection.detection_items: - if compile(pattern = "\\w+\\s+\\w+").match(detection_item.field): - detection_item.field = detection_item.field.replace(" ", "") - def powershell_pipeline() -> ProcessingPipeline: return ProcessingPipeline( name = "PowerShell pipeline", @@ -35,7 +24,7 @@ def powershell_pipeline() -> ProcessingPipeline: ProcessingItem( rule_condition_negation = True, rule_conditions = [LogsourceCondition(product = "windows")], - transformation = RuleFailureTransformation("Product not supported.") + transformation = RuleFailureTransformation(message = "Product not supported.") ) ] + [ ProcessingItem( @@ -64,11 +53,7 @@ def powershell_pipeline() -> ProcessingPipeline: ) ] + [ ProcessingItem( - transformation = RemoveWhiteSpaceTransformation() - ) - ] + [ - ProcessingItem( - transformation = AddFieldnamePrefixTransformation("$_.") + transformation = AddFieldnamePrefixTransformation(prefix = "$_.") ) ] ) \ No newline at end of file diff --git a/sigma2powershell.py b/sigma2powershell.py index 541d55d..f99aa4c 100644 --- a/sigma2powershell.py +++ b/sigma2powershell.py @@ -1,20 +1,29 @@ +from argparse import ArgumentParser from sigma.collection import SigmaCollection from sigma.pipelines.powershell import powershell_pipeline from sigma.backends.powershell import PowerShellBackend -import argparse +from subprocess import Popen, PIPE -def Sigma2PowerShell(path: str, show_errors: bool): +output_formats = "default", "script" + +def Sigma2PowerShell(path: str, show_errors: bool, foo: str): rules = SigmaCollection.load_ruleset(inputs = [path]) pipeline = powershell_pipeline() backend = PowerShellBackend(processing_pipeline = pipeline, collect_errors = show_errors) - return backend.convert(rule_collection = rules, output_format = "default") + return backend.convert(rule_collection = rules, output_format = foo) + +def execute(ps_command): + process = Popen(["powershell", "-Command", ps_command], stdout = PIPE, stderr = PIPE, text = True) + output, error = process.communicate() + print("Output:", output) + print("Error:", error) if "__main__" == __name__: - parser = argparse.ArgumentParser() - parser.add_argument("-p", "--path", help = "path to Sigma rule(s)", type = str) - # parser.add_argument("-o", "--output", choices = output_formats, default = "default", help = "output format", type = str) - parser.add_argument("-e", "--show-errors", action = "store_false", default = True, help = "show rule errors") + parser = ArgumentParser() + parser.add_argument("-p", help = "path to Sigma rule(s)", type = str) + parser.add_argument("-o", choices = output_formats, default = "default", help = "output format", type = str) + parser.add_argument("-e", action = "store_false", default = True, help = "show rule errors") args = parser.parse_args() - queries = Sigma2PowerShell(args.path, args.show_errors) + queries = Sigma2PowerShell(args.p, args.e, args.o) if None not in queries: print("\n".join(queries)) \ No newline at end of file